2013-08-26 54 views
6

我想在运行时动态地在代码中调整机器密钥,用于IIS托管的ASP.NET MVC 4网站。代码中的ASP.NET机器密钥设置密钥

机器密钥,加密和验证密钥以及要使用的算法存储在数据库中。我不想从web.config文件中读取值,而是想在应用程序启动过程中注入这些值,并让系统使用这些值。

有什么办法可以完成,而不必改变web.config(只改变内存配置)?

我试过访问配置部分,但它被标记为只读,并且也被密封,所以我不能覆盖IsReadOnly()。但是,对我而言,有一个setter这是一个指示器,可能有办法删除只读标志。

var configSection = (MachineKeySection)ConfigurationManager.GetSection("system.web/machineKey"); 
if (!configSection.IsReadOnly()) 
{ 
     configSection.ValidationKey = _platformInfo.MachineKey.ValidationKey; 
     configSection.DecryptionKey = _platformInfo.MachineKey.EncryptionKey; 
     ... 
} 

有没有什么办法可以做到这一点? 我能看到的唯一选择是使用像AppHarbor这样的自定义方法,但是如果可能的话,我宁愿坚持内置方法。

如果有人问我为什么要这样做,原因是, 这是针对大量相同的网站在网站群中运行。因此,具有非自动生成的密钥是必须的(每个服务器上必须是相同的)。每个网站也应该被隔离,不应该共享相同的密钥。由于所有网站的物理表示都相同,因此它们共享相同的物理位置。这就是web.config文件不能包含应用程序特定设置的原因。

编辑:如果确实无法完成,至少应该确认一下。如上所述,人们可以使用自定义身份验证和加密方法来避免完全使用机器密钥设置。谢谢。

回答

5

一旦Web应用程序启动,就没有办法以编程方式设置它。但是,仍然有可能实现您的目标。

如果每个应用程序在其自己的应用程序池正在运行,如果每个应用程序池都有自己的身份,然后在applicationHost.config检查出CLRConfigFile开关。您可以使用此每个应用程序池来注入新的配置级别。有关如何使用此示例的示例,请参阅http://weblogs.asp.net/owscott/archive/2011/12/01/setting-an-aspnet-config-file-per-application-pool.aspx。您可以在每个应用程序池的自定义CLR配置文件中设置显式且唯一的system.web/machineKey >元素。

这是Azure网站,GoDaddy和其他需要在每个应用程序基础上设置默认显式机器密钥的主机所使用的机制。请记住,要为将访问它的应用程序池适当地ACL每个目标.config文件。

+0

感谢了很多,帮助我(和希望其他人也是如此)。通常较大的网站使用单独的应用程序池。但较小的网站可能共享应用程序池。但正是我所需要的,因为我可以围绕这个建立起来。 – michael81

+0

定制CLR配置文件的结构应该是“/configuration/system.web/machineKey”吗?有没有办法显示或测试应用程序上的实际machineKey值,以确认自定义CLR配置文件实际上是否正确生效? – John

+0

是的。您可以使用ConfigurationManager.GetSection(“system.web/machineKey”),将返回的对象转换为MachineKeySection,并查看挂起的属性以验证您的更改是否正确拾取。 – Levi

2

这是丑陋的,但我可以使用反射来暂时从配置部分只读位,设置的加密密钥,然后将其还原:

var getter = typeof(MachineKeySection).GetMethod("GetApplicationConfig", BindingFlags.Static | BindingFlags.NonPublic); 
var config = (MachineKeySection)getter.Invoke(null, Array.Empty<object>()); 

var readOnlyField = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); 
readOnlyField.SetValue(config, false); 

config.DecryptionKey = myKeys.EncryptionKey; 
config.ValidationKey = myKeys.ValidationKey; 

readOnlyField.SetValue(config, true);