EF连接字符串加密及封装
参考链接: 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项目是两个解决方案,上述操作做完的时候,运行可能会报错,这是需要引用两个带来了文件,就会解决