在研究之后,我能够使用 IIS Express 和重写 Controller 类的 OnAuthorization 方法(Ref#1)来解决这个问题。我也选择了 Hanselman 推荐的路线(Ref#2)。但是,由于两个原因,我对这两种解决方案并不完全满意:
1. Ref#1 的 OnAuthorization 只在动作级别起作用,在控制器类级别不起作用
2. Ref#2 需要大量设置(用于 makecert 的 Win7 SDK)、netsh 命令,并且,为了使用端口 80 和端口 443,我需要以管理员身份启动 VS2010,我不赞成。
所以,我想出了这个解决方案,它专注于简单性,满足以下条件:
我希望能够在 Controller 类或操作级别使用 RequireHttps attbbute
我希望 MVC 在 RequireHttps 属性存在时使用 HTTPS,如果不存在则使用 HTTP
我不想以管理员身份运行 Visual Studio
我希望能够使用由 IIS Express 分配的任何 HTTP 和 HTTPS 端口(参见注释#1)
我可以重用IIS Express的自签名SSL证书,我不在乎是否看到无效的SSL提示
-
我希望开发、测试和生产具有完全相同的代码库和相同的二进制文件,并且尽可能独立于其他设置(例如使用 netsh、mmc 证书管理单元等)
现在,有了背景和解释,我希望这段代码可以帮助别人并节省一些时间。基本上,创建一个继承自 Controller 的 BaseController 类,并从该基类派生您的控制器类。既然你已经读了这么多,我假设你知道如何做这些。所以,编码愉快!
注意#1:这是通过使用有用的函数“getConfig”来实现的(参见代码)
参考#1:http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
参考#2:http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx
========== BaseController 中的代码 ===================
#region Override to reroute to non-SSL port if controller action does not have RequireHttps attribute to save on CPU
// By L. Keng, 2012/08/27
// Note that this code works with RequireHttps at the controller class or action level.
// Credit: Various stackoverflow.com posts and http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
protected override void OnAuthorization(AuthorizationContext filterContext)
{
// if the controller class or the action has RequireHttps attribute
var requireHttps = (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0
|| filterContext.ActionDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0);
if (Request.IsSecureConnection)
{
// If request has a secure connection but we don't need SSL, and we are not on a child action
if (!requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "http",
Port = int.Parse(getConfig("HttpPort", "80")) // grab from config; default to port 80
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
else
{
// If request does not have a secure connection but we need SSL, and we are not on a child action
if (requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "https",
Port = int.Parse(getConfig("HttpsPort", "443")) // grab from config; default to port 443
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
base.OnAuthorization(filterContext);
}
#endregion
// a useful helper function to get appSettings value; allow caller to specify a default value if one cannot be found
internal static string getConfig(string name, string defaultValue = null)
{
var val = System.Configuration.ConfigurationManager.AppSettings[name];
return (val == null ? defaultValue : val);
}
==============结束码================
在 Web.Release.Config 中,添加以下内容以清除 HttpPort 和 HttpsPort(使用默认的 80 和 443)。
<appSettings>
<add key="HttpPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
<add key="HttpsPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
</appSettings>