如何在基于ASP.NET MVC的网站中为某些页面使用HTTPS?ASP.NET MVC下的SSL页面
史蒂夫·桑德森对如何在做到这一点在干燥的方式上预览4一个不错的教程:
http://blog.codeville.net/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/
是否与预览5?
如何在基于ASP.NET MVC的网站中为某些页面使用HTTPS?ASP.NET MVC下的SSL页面
史蒂夫·桑德森对如何在做到这一点在干燥的方式上预览4一个不错的教程:
http://blog.codeville.net/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/
是否与预览5?
如果您正在使用ASP.NET MVC 2 Preview 2 or higher,你现在可以简单地使用:
[RequireHttps]
public ActionResult Login()
{
return View();
}
虽然,命令的参数值得注意的是,作为mentioned here。
更好/更新的方式有些ActionLink的扩展:http://www.squaredroot.com/post/2008/06/11/MVC-and-SSL.aspx 或者重定向到https的控制器action属性:// http://forums.asp.net/p/1260198/2358380.aspx#2358380
这里有一个blog post by Pablo M. Cibrano˚F rom 2009年1月收集了一些技巧,包括HttpModule和扩展方法。
这是使用ActionFilter的blog post by Adam Salvo。
确保你看到他自己写的后续文章:http://blog.salvoz.com/2009/04/25/PartialSSLAndAuthorizationWithAspNetMVCRevisited.aspx – 2009-07-12 19:49:55
MVCFutures有'RequireSSL'属性。
(感谢亚当为pointing that out在更新的博文)
只要将它应用到你的操作方法,以“重定向=真正的”如果你想要一个http://请求自动变成https://开头:
[RequireSsl(Redirect = true)]
我是否需要继承它以处理本地主机请求? – 2009-11-05 02:46:41
一种方法是为本地机器创建证书并使用它。我认为完全禁用它的本地主机,你确实需要子类或重复的代码。不知道推荐的方法是什么 – 2009-11-05 07:46:34
看起来它是密封的,所以我需要重复代码。游民。 本地机器的证书只能在IIS中正常工作,而不是开发Web服务器。 – 2009-11-05 16:55:48
下面是从丹Wahlin最近的文章对这个:
http://weblogs.asp.net/dwahlin/archive/2009/08/25/requiring-ssl-for-asp-net-mvc-controllers.aspx
他使用ActionFilter属性。
由于Amadiere wrote,[RequireHttps]在MVC 2 进入 HTTPS的伟大工程。但是,如果您只想按照您的说法使用HTTPS 一些页面,那么MVC 2不会给您任何爱 - 一旦它将用户切换到HTTPS,它们就会一直停留在那里,直到您手动重定向它们。
我使用的方法是使用另一个自定义属性[ExitHttpsIfNotRequired]。当连接到控制器或动作,这将重定向到HTTP如果:
这里有点太大而不能在这里发布,但你可以看到the code here加上一些额外的细节。
这不一定是MVC具体的,但这种方法确实工作既ASP.NET WebForms和MVC:
http://www.codeproject.com/KB/web-security/WebPageSecurity_v2.aspx
我已经使用了好几年,并像关注分离和通过web.config文件进行管理。
对于那些谁不是面向属性的开发方法风扇,这里是一段代码,可以帮助:
public static readonly string[] SecurePages = new[] { "login", "join" };
protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
var pageName = RequestHelper.GetPageNameOrDefault();
if (!HttpContext.Current.Request.IsSecureConnection
&& (HttpContext.Current.Request.IsAuthenticated || SecurePages.Contains(pageName)))
{
Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"] + HttpContext.Current.Request.RawUrl);
}
if (HttpContext.Current.Request.IsSecureConnection
&& !HttpContext.Current.Request.IsAuthenticated
&& !SecurePages.Contains(pageName))
{
Response.Redirect("http://" + Request.ServerVariables["HTTP_HOST"] + HttpContext.Current.Request.RawUrl);
}
}
有几个原因,以避免属性,其中之一是,如果你想要查看所有受保护页面的列表,您必须跳过解决方案中的所有控制器。
我去翻过这个问题,希望我的解决方案可以帮助别人。
我们得到了几个问题: - 我们需要保护的具体行动,例如“登录”,在“帐户”。我们可以使用RequireHttps属性中的构建,这非常棒 - 但它会使用https://重定向到我们。 - 我们应该制作我们的链接,表单和诸如“SSL知晓”。
一般情况下,我的解决方案允许指定将使用绝对URL,除了指定协议的能力路线。您可以使用此批准来指定“https”协议。
所以,首先我创建了一个ConnectionProtocol枚举:
/// <summary>
/// Enum representing the available secure connection requirements
/// </summary>
public enum ConnectionProtocol
{
/// <summary>
/// No secure connection requirement
/// </summary>
Ignore,
/// <summary>
/// No secure connection should be used, use standard http request.
/// </summary>
Http,
/// <summary>
/// The connection should be secured using SSL (https protocol).
/// </summary>
Https
}
RequireSsl的现在,我已经创建手卷版本。我修改了原始的RequireSsl源代码,允许重定向回http:// urls。另外,我已经把一个领域,使我们能够确定我们是否应该要求SSL或没有(我用它与DEBUG预处理器)。现在
/* Note:
* This is hand-rolled version of the original System.Web.Mvc.RequireHttpsAttribute.
* This version contains three improvements:
* - Allows to redirect back into http:// addresses, based on the <see cref="SecureConnectionRequirement" /> Requirement property.
* - Allows to turn the protocol scheme redirection off based on given condition.
* - Using Request.IsCurrentConnectionSecured() extension method, which contains fix for load-balanced servers.
*/
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class RequireHttpsAttribute : FilterAttribute, IAuthorizationFilter
{
public RequireHttpsAttribute()
{
Protocol = ConnectionProtocol.Ignore;
}
/// <summary>
/// Gets or sets the secure connection required protocol scheme level
/// </summary>
public ConnectionProtocol Protocol { get; set; }
/// <summary>
/// Gets the value that indicates if secure connections are been allowed
/// </summary>
public bool SecureConnectionsAllowed
{
get
{
#if DEBUG
return false;
#else
return true;
#endif
}
}
public void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
/* Are we allowed to use secure connections? */
if (!SecureConnectionsAllowed)
return;
switch (Protocol)
{
case ConnectionProtocol.Https:
if (!filterContext.HttpContext.Request.IsCurrentConnectionSecured())
{
HandleNonHttpsRequest(filterContext);
}
break;
case ConnectionProtocol.Http:
if (filterContext.HttpContext.Request.IsCurrentConnectionSecured())
{
HandleNonHttpRequest(filterContext);
}
break;
}
}
private void HandleNonHttpsRequest(AuthorizationContext filterContext)
{
// only redirect for GET requests, otherwise the browser might not propagate the verb and request
// body correctly.
if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The requested resource can only be accessed via SSL.");
}
// redirect to HTTPS version of page
string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
filterContext.Result = new RedirectResult(url);
}
private void HandleNonHttpRequest(AuthorizationContext filterContext)
{
if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The requested resource can only be accessed without SSL.");
}
// redirect to HTTP version of page
string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
filterContext.Result = new RedirectResult(url);
}
}
,这RequireSsl将做您的要求以下基本属性值: - 忽略:不会做什么。 - Http:将强制重定向到http协议。 - Https:将强制重定向到https协议。
你应该建立自己的基地控制器和设置该属性为HTTP。
[RequireSsl(Requirement = ConnectionProtocol.Http)]
public class MyController : Controller
{
public MyController() { }
}
现在,在每个需要SSL的cpntroller/action中,只需使用ConnectionProtocol.Https设置此属性即可。
现在让我们转移到网址:我们得到了与URL路由引擎几个问题。您可以通过http://blog.stevensanderson.com/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/了解更多关于它们的信息。在这篇文章中提出的解决方案理论上很好,但很老,我不喜欢这种方法。
我的解决方案如下: 创建基本的 “路” 类的子类:
公共类AbsoluteUrlRoute:路线 { #地区的构造函数
/// <summary>
/// Initializes a new instance of the System.Web.Routing.Route class, by using
/// the specified URL pattern and handler class.
/// </summary>
/// <param name="url">The URL pattern for the route.</param>
/// <param name="routeHandler">The object that processes requests for the route.</param>
public AbsoluteUrlRoute(string url, IRouteHandler routeHandler)
: base(url, routeHandler)
{
}
/// <summary>
/// Initializes a new instance of the System.Web.Routing.Route class, by using
/// the specified URL pattern and handler class.
/// </summary>
/// <param name="url">The URL pattern for the route.</param>
/// <param name="defaults">The values to use for any parameters that are missing in the URL.</param>
/// <param name="routeHandler">The object that processes requests for the route.</param>
public AbsoluteUrlRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
: base(url, defaults, routeHandler)
{
}
/// <summary>
/// Initializes a new instance of the System.Web.Routing.Route class, by using
/// the specified URL pattern and handler class.
/// </summary>
/// <param name="url">The URL pattern for the route.</param>
/// <param name="defaults">The values to use for any parameters that are missing in the URL.</param>
/// <param name="constraints">A regular expression that specifies valid values for a URL parameter.</param>
/// <param name="routeHandler">The object that processes requests for the route.</param>
public AbsoluteUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
IRouteHandler routeHandler)
: base(url, defaults, constraints, routeHandler)
{
}
/// <summary>
/// Initializes a new instance of the System.Web.Routing.Route class, by using
/// the specified URL pattern and handler class.
/// </summary>
/// <param name="url">The URL pattern for the route.</param>
/// <param name="defaults">The values to use for any parameters that are missing in the URL.</param>
/// <param name="constraints">A regular expression that specifies valid values for a URL parameter.</param>
/// <param name="dataTokens">Custom values that are passed to the route handler, but which are not used
/// to determine whether the route matches a specific URL pattern. These values
/// are passed to the route handler, where they can be used for processing the
/// request.</param>
/// <param name="routeHandler">The object that processes requests for the route.</param>
public AbsoluteUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
RouteValueDictionary dataTokens, IRouteHandler routeHandler)
: base(url, defaults, constraints, dataTokens, routeHandler)
{
}
#endregion
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var virtualPath = base.GetVirtualPath(requestContext, values);
if (virtualPath != null)
{
var scheme = "http";
if (this.DataTokens != null && (string)this.DataTokens["scheme"] != string.Empty)
{
scheme = (string) this.DataTokens["scheme"];
}
virtualPath.VirtualPath = MakeAbsoluteUrl(requestContext, virtualPath.VirtualPath, scheme);
return virtualPath;
}
return null;
}
#region Helpers
/// <summary>
/// Creates an absolute url
/// </summary>
/// <param name="requestContext">The request context</param>
/// <param name="virtualPath">The initial virtual relative path</param>
/// <param name="scheme">The protocol scheme</param>
/// <returns>The absolute URL</returns>
private string MakeAbsoluteUrl(RequestContext requestContext, string virtualPath, string scheme)
{
return string.Format("{0}://{1}{2}{3}{4}",
scheme,
requestContext.HttpContext.Request.Url.Host,
requestContext.HttpContext.Request.ApplicationPath,
requestContext.HttpContext.Request.ApplicationPath.EndsWith("/") ? "" : "/",
virtualPath);
}
#endregion
}
此版本的 “路线” 的类将创建绝对网址。这里的诀窍,以及博客文章作者的建议,是使用DataToken来指定方案(例如结尾:))。
现在,如果我们要生成一个url,例如路径“Account/LogOn”,我们会得到“/ http://example.com/Account/LogOn” - 这是因为UrlRoutingModule将所有的url视为相对的。我们可以修复使用自定义的HttpModule:
public class AbsoluteUrlRoutingModule : UrlRoutingModule
{
protected override void Init(System.Web.HttpApplication application)
{
application.PostMapRequestHandler += application_PostMapRequestHandler;
base.Init(application);
}
protected void application_PostMapRequestHandler(object sender, EventArgs e)
{
var wrapper = new AbsoluteUrlAwareHttpContextWrapper(((HttpApplication)sender).Context);
}
public override void PostResolveRequestCache(HttpContextBase context)
{
base.PostResolveRequestCache(new AbsoluteUrlAwareHttpContextWrapper(HttpContext.Current));
}
private class AbsoluteUrlAwareHttpContextWrapper : HttpContextWrapper
{
private readonly HttpContext _context;
private HttpResponseBase _response = null;
public AbsoluteUrlAwareHttpContextWrapper(HttpContext context)
: base(context)
{
this._context = context;
}
public override HttpResponseBase Response
{
get
{
return _response ??
(_response =
new AbsoluteUrlAwareHttpResponseWrapper(_context.Response));
}
}
private class AbsoluteUrlAwareHttpResponseWrapper : HttpResponseWrapper
{
public AbsoluteUrlAwareHttpResponseWrapper(HttpResponse response)
: base(response)
{
}
public override string ApplyAppPathModifier(string virtualPath)
{
int length = virtualPath.Length;
if (length > 7 && virtualPath.Substring(0, 7) == "/http:/")
return virtualPath.Substring(1);
else if (length > 8 && virtualPath.Substring(0, 8) == "/https:/")
return virtualPath.Substring(1);
return base.ApplyAppPathModifier(virtualPath);
}
}
}
}
由于该模块是压倒UrlRoutingModule的基本实现,我们应该卸下底座HTTP模块,并在web.config中注册我们的。所以,在“system.web”下设置:
<httpModules>
<!-- Removing the default UrlRoutingModule and inserting our own absolute url routing module -->
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="MyApp.Web.Mvc.Routing.AbsoluteUrlRoutingModule" />
</httpModules>
那就是:)。
为了注册一个绝对/协议遵循的路线,你应该做的:
routes.Add(new AbsoluteUrlRoute("Account/LogOn", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new {controller = "Account", action = "LogOn", area = ""}),
DataTokens = new RouteValueDictionary(new {scheme = "https"})
});
会喜欢听到你的反馈+的改进。希望它可以帮助! :)
编辑: 我忘了包括IsCurrentConnectionSecured()扩展方法(太多的片段:P)。这是一种通常使用Request.IsSecuredConnection的扩展方法。然而,当使用负载均衡时,这种方法无效 - 所以这种方法可以绕过这个(从nopCommerce中获取)。
/// <summary>
/// Gets a value indicating whether current connection is secured
/// </summary>
/// <param name="request">The base request context</param>
/// <returns>true - secured, false - not secured</returns>
/// <remarks><![CDATA[ This method checks whether or not the connection is secured.
/// There's a standard Request.IsSecureConnection attribute, but it won't be loaded correctly in case of load-balancer.
/// See: <a href="http://nopcommerce.codeplex.com/SourceControl/changeset/view/16de4a113aa9#src/Libraries/Nop.Core/WebHelper.cs">nopCommerce WebHelper IsCurrentConnectionSecured()</a>]]></remarks>
public static bool IsCurrentConnectionSecured(this HttpRequestBase request)
{
return request != null && request.IsSecureConnection;
// when your hosting uses a load balancer on their server then the Request.IsSecureConnection is never got set to true, use the statement below
// just uncomment it
//return request != null && request.ServerVariables["HTTP_CLUSTER_HTTPS"] == "on";
}
MVC 6(ASP.NET核心1.0)正在与Startup.cs略有不同。
要在所有页面上使用RequireHttpsAttribute(如Amadiere的answer中所述),您可以将其添加到Startup.cs中,而不是在每个控制器上使用属性样式(或者不是为所有控制器创建一个BaseController来继承) 。
Startup.cs - 注册过滤器:
public void ConfigureServices(IServiceCollection services)
{
// TODO: Register other services
services.AddMvc(options =>
{
options.Filters.Add(typeof(RequireHttpsAttribute));
});
}
有关的设计决定了上述方法的详细信息,请参阅我在类似的问题有关how to exclude localhost requests from being handled by the RequireHttpsAttribute答案。
这是非常过时的。对于MVC4及更高版本,请参阅我的博文http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new -allowanonymous-attribute.aspx – RickAndMSFT 2014-02-19 02:15:51