參考鏈接: https://blog.csdn.net/shujudeliu/article/details/80692403
我們做如下准備工作:
1.創建一個名稱為“Web_Ado”的解決方案
2.在解決方案中添加一個名稱為“EFModel”類庫子項目、一個名稱為“EFModel”類庫子項目
3.在“Test.DB”子項目中添加“ADO.NET實體數據模型”,命名為“Model2.edmx”,然后在彈出的“實體模型向導”中,選擇從數據庫生成,新建連接→連接屬性,輸入數據庫服務器的ip、用戶名、密碼、指定數據庫,然后選擇“是,在連接字符串中包含敏感數據”,將App.Config中的實體鏈接另存為Model2Container,然后勾選數據庫中的表
打開Model2.Container.cs
可以看到如下代碼:
public partial class Model2Container : DbContext { public Model2Container() : base("name=Model2Container") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { throw new UnintentionalCodeFirstException(); } public virtual DbSet<Products> Products { get; set; } public virtual DbSet<TreeMenu> TreeMenu { get; set; } public virtual DbSet<Users> Users { get; set; } }
這里的TestEntities實體對象繼承自DbContext對象,構造函數繼承自父類DbContext,如果VS里安裝了.net reflector插件F12轉到定義就可以看到DbContext類里讀取的是App.Config中的<connectionStrings>節的配置。
我們考慮的連接字符串加密是:使用對稱加密算法把連接字符串進行加密后放入App.Config配置文件中,創建數據庫實體對象時先對連接字符串解密,然后使用解密后的連接字符串進行創建。
由於創建數據庫實體對象TestEntities時向導自動創建無參的構造函數調用的實際是父類DbContext中的構造方法,我們沒辦法對父類DbContext做修改,那么就只能對TestEntities類的構造函數進行重載,但是該類是是通過向導自動生成的,直接在類里修改明顯不合適(重新自動生成時我們做的修改會被覆蓋掉),但是可以看到TestEntities類修飾符是帶有partial關鍵字的,即該類是一個分部類,我們可以新建一個同名分部類來對該類進行擴展:
創建同名類Model2db.cs
using System; using System.Collections.Generic; using System.Configuration; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EFModel { public partial class Model2Container : DbContext { public Model2Container(string connectionStr) : base(connectionStr) { } } }
該類包含一個有參構造函數,在使用該構造函數創建EF實體對象時不會直接從App.Config中讀取,而是由我們指定傳入。
還需要我們在創建一個DBContentxHelper幫助類,用於解密/加密獲取的webconfig鏈接字符串的文件
public static class Model2Helper { public static Model2Container GetDBContext() { string cnnstr = ConfigurationManager.ConnectionStrings["Model2Container"].ConnectionString;//獲取webconfig中鏈接字符串 string cnstr = new SymmetricMethod().Decrypto(cnnstr);//解密 return new Model2Container(cnstr); } }
二、EF連接字符串加密——加密與封裝
我們使用上篇.net reactor的使用中創建的項目來加密解密連接字符串。但是怎么達到封裝的目的呢?
為了達到封裝的目的,加密類方法的修飾符要做下調整,由public調整為internal(若是兩個解決方案需要用public),即限制本項目內使用:
創建一個SymmetricMethod類,用於做加密和解密:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace EFModel { //密碼生成:https://suijimimashengcheng.51240.com/ //internal public class SymmetricMethod { private SymmetricAlgorithm mobjCryptoService; private string Key; /// <summary> /// 對稱加密類的構造函數 internal /// </summary> public SymmetricMethod() { mobjCryptoService = new RijndaelManaged(); Key = "FefZ$@pAedzg#HjT!QcM7JQqwOcAkCm7x2pZjBUMSocM9v6#%AP9HZg7OZ^ogG!x"; } /// <summary> /// 獲得密鑰 /// </summary> /// <returns>密鑰</returns> private byte[] GetLegalKey() { string sTemp = Key; mobjCryptoService.GenerateKey(); byte[] bytTemp = mobjCryptoService.Key; int KeyLength = bytTemp.Length; if (sTemp.Length > KeyLength) sTemp = sTemp.Substring(0, KeyLength); else if (sTemp.Length < KeyLength) sTemp = sTemp.PadRight(KeyLength, ' '); return ASCIIEncoding.ASCII.GetBytes(sTemp); } /// <summary> /// 獲得初始向量IV /// </summary> /// <returns>初試向量IV</returns> private byte[] GetLegalIV() { string sTemp = "XUYXqW8QF2fqyytf0ZwU6Vv1cbNI3qU!zVzohQ0ptAug#&uJ3b^rEKkrckH1LE3i"; mobjCryptoService.GenerateIV(); byte[] bytTemp = mobjCryptoService.IV; int IVLength = bytTemp.Length; if (sTemp.Length > IVLength) sTemp = sTemp.Substring(0, IVLength); else if (sTemp.Length < IVLength) sTemp = sTemp.PadRight(IVLength, ' '); return ASCIIEncoding.ASCII.GetBytes(sTemp); } /// <summary> /// 加密方法 internal /// </summary> /// <param name="Source">待加密的串</param> /// <returns>經過加密的串</returns> public string Encrypto(string Source) { byte[] bytIn = UTF8Encoding.UTF8.GetBytes(Source); MemoryStream ms = new MemoryStream(); mobjCryptoService.Key = GetLegalKey(); mobjCryptoService.IV = GetLegalIV(); ICryptoTransform encrypto = mobjCryptoService.CreateEncryptor(); CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write); cs.Write(bytIn, 0, bytIn.Length); cs.FlushFinalBlock(); ms.Close(); byte[] bytOut = ms.ToArray(); return Convert.ToBase64String(bytOut); } /// <summary> /// 解密方法 internal /// </summary> /// <param name="Source">待解密的串</param> /// <returns>經過解密的串</returns> public string Decrypto(string Source) { byte[] bytIn = Convert.FromBase64String(Source); MemoryStream ms = new MemoryStream(bytIn, 0, bytIn.Length); mobjCryptoService.Key = GetLegalKey(); mobjCryptoService.IV = GetLegalIV(); ICryptoTransform encrypto = mobjCryptoService.CreateDecryptor(); CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read); StreamReader sr = new StreamReader(cs); return sr.ReadToEnd(); } } }
接下來在控制器中測試:
//EFModel.Model2db db = new EFModel.Model2db(""); EFModel.Model2Container db =EFModel.Model2Helper.GetDBContext(); public ActionResult Index() { //string sss="metadata=res://*/Model2.csdl|res://*/Model2.ssdl|res://*/Model2.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=cesi;user id=sa;password=000;MultipleActiveResultSets=True;App=EntityFramework""; //string EnSSS = new EFModel.SymmetricMethod().Encrypto(sss); var p = db.Products.FirstOrDefault(); string name= p.ProductName; name = name + ""; return View(p); }
看下webconfig中的鏈接
<connectionStrings> <add name="Model2Container" connectionString="tnyrLxN6i4y1GZ5JiS8XpL9OmJf9+4yk7V/XcmK9O0FEZUVMXqR+GphenP1Ot9JekUlShNbWo7HyJvbMnzhi9kStMdBzLFMENiuoJj3uCWAq0UWE6S5/dPHqFR35G/kWflvfZ6aBtdyB74SnvOEwRPQ6FpbHQD/c23zTOIfZwQd4tMVF8/mQ9ciH/ZEEMMaeAPARsstPvRdRMhYlrRp4gt4gQxD//l/sFtorhcPdUxalU/myKCrU/zaUL+3+4acIP3JtGZOF0SkK01cABUXUXjF6fb9MgWn6Jbo/rjavgiUgGX+UGZke1aPyyymNe2+6" providerName="System.Data.EntityClient" /> </connectionStrings>
注意: 如果是實體數據模型跟MVC項目是兩個解決方案,上述操作做完的時候,運行可能會報錯,這是需要引用兩個帶來了文件,就會解決