浅谈 EF WebConfig 的加密
不管是否采用EF框架,创建的站点大多数情况下都会在位于站点根目录下的 WebConfig 内添加与数据库有关的敏感内容,例如数据库连接字符串,该连接串会暴露你的数据库角色账号及密码,尽管在WebConfig 内添加各种资源节点有助于统一管理及维护,笔者认为其最大的好处在于满足运行时的动态配置,但避免不了信息暴露的安全性隐患!严格来说作为开发者不需要关心站点文件的安全性问题,因为这是运维人员部署站点时需要做的事情,如果是Windows服务器的话,只要给站点目录做安全策略和用户权限控制即可。
笔者感觉网上大多资料描述不够清楚或过于复杂,在此笔者使用一个 Dictionary 对象实现装载多个数据库连接字符串节点的装载,如此一来便不需要在AppConfig和WebConfig中写入连接字串。
如下所示,当你采用EF自动生成数据库抽象模型后,VS自动在你的 WebConfig 内添加了类似的连接字符串。
<connectionStrings> <add name="DBConnText_1" connectionString="metadata="res://*/Entity Data Model.00.DB_00.csdl|res://*/Entity Data Model.**.**.ssdl|res://*/Entity Data Model.**.**.msl"; provider=Oracle.ManagedDataAccess.Client; provider connection string="DATA SOURCE=192.13.11.102:1521/00; PASSWORD=006tsl;PERSIST SECURITY INFO=True; USER ID=abc providerName="System.Data.EntityClient" /> </connectionStrings>
接下来我们看看读写操作代码中是如何实例化和使用EF数据库操作对象的:
using (DBEntities entity = new DBEntities()) { IQueryable<TB1> Iquery = entity.TB1.Where(x => (x.userName == “ABC”)); if(Iquery.Count() > 0) { …… } }
由红色标注部分可以看到,操作对象通过采用一个无参构造函数实现数据库连接并实例化数据库操作对象的,所以我们需要修改该构造函数达到目的。先来看看该构造函数:
public DBEntities() : base("name=DBConnText_1", "DBEntities") { this.ContextOptions.LazyLoadingEnabled = true; OnContextCreated(); }
自动生成的还有下面两个版本,一个是传入标准的数据库连接字符串,另一个是传入EF自有的数据库连接对象。
版本1:
DBEntities(string connectionString) : base(connectionString, "DBEntities") { ... }
版本2:
DBEntities(EntityConnection connection) : base(connection, "DBEntities") { ... }
以面向对象的思维考虑,笔者更喜欢采用通过实例化并传入一个 EntityConnection 对象的方式构建数据库读写器,但有一点不好的地方是采用这个版本的构造函数,你必须在业务层每次需要操作数据库并试图构建一个数据库读写器时都要显式传入一个EntityConnection 对象,对于有代码简洁癖或者说希望少写点代码的我来说,还是放弃这个方法了。扯远了,让我们回到无参构造函数中去。
DBEntities() : base("name=DBConnText_1", "DBEntities")
这个版本的构造函数不需要传入任何参数,而是通过父类的构造函数显式指定了位于AppConfig和WebConfig中的数据库连接字符串节点名实现构建,也就是说 name=DBConnText_1 实际上是父类跑去Webconfig读取名为 DBConnText_1 的数据库连接字符串,实际上也是为了得到一个连接字符串。于是我们可以这样修改——把WebConfig中的连接串内容搬到这里实现构建,从而使得WebConfig不再需要写入该连接串。修改如下所示:
DBEntities() : base("metadata=\"rmetadata=res://*/DBEdmx.csdl|res://*/DBEdmx.ssdl|res://*/DBEdmx.msl;provider=System.Data.……\"", "DBEntities")
好吧,我承认上面说的都是不重要的,而且大概你也想到了,尽管采用这样的方式便不再需要在WebConfig写入连接串了,但却牺牲了多个数据库连接串节点易于维护管理的特性,也就是说如果你仍然通过在WebConfig中以连接串节点的形式描述多个数据库连接的话,至少后面你的业务层仅仅通过更换一下节点名即可实现连接不同数据库了。为了增加易于维护管理的特性,这里我们引入Dictionary ,利用Dictionary (字典)对多个数据库连接串进行归纳装载,当我们需要更换不同数据库进行连接的时候,只需要根据字典的Key获取对应数据库连接串即可。
笔者先创建一个 DBConfig 的自定义类,类内部采用Dictionary 装载多个数据库连接串,并在构造函数内部通过传入的参数名作为字典的Key,获取Dictionary对应的数据库连接串。
public static class DBConfig { private static Dictionary<string, string> dictConnStr = new Dictionary<string, string>() { {"DB1","metadata=res://*/DBEdmx.csdl|res://*/DBEdmx.ssdl|res://*/DBEdmx.msl;provider=System.Data.SqlClient;provider connection string=\"data source=192.168.1.121,1433;initial catalog=DB1;user id=sa;password=123456;multipleactiveresultsets=True;App=EntityFramework\""}, {"DB2","metadata=res://*/DBEdmx.csdl|res://*/DBEdmx.ssdl|res://*/DBEdmx.msl;provider=System.Data.SqlClient;provider connection string=\"data source=192.168.2.122,1433;initial catalog=DB2;user id=sa;password=123456;multipleactiveresultsets=True;App=EntityFramework\""}, {"DB3","metadata=res://*/DBEdmx.csdl|res://*/DBEdmx.ssdl|res://*/DBEdmx.msl;provider=System.Data.SqlClient;provider connection string=\"data source=192.168.3.123,1433;initial catalog=DB3;user id=sa;password=123456;multipleactiveresultsets=True;App=EntityFramework\""}, }; public static string DBConnString(string configName) { return dictConnStr.ContainsKey(configName) ? dictConnStr[configName] : string.Empty; } }
DBEntities 的构造函数修改如下:
//使用DB2的数据库连接串构建数据库读写器 public DBEntities() : base(DBConfig.DBConnString("DB2"), "DBEntities") { this.ContextOptions.LazyLoadingEnabled = true; OnContextCreated(); }
内容就到这里了,觉得不错的话点个赞哦~摸摸哒