在ASP.NET MVC SSL页(SSL pages under ASP.NET MVC)

2019-08-18 02:00发布

我该如何去使用HTTPS对于一些在我的基于ASP.NET MVC网站的网页吗?

史蒂夫·桑德森对如何做到这一点在上预览4干法一个不错的教程:

http://blog.codeville.net/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/

是否与预览5更好/更新的方式?

Answer 1:

如果你正在使用ASP.NET MVC 2预览版2或更高版本 ,现在可以简单地使用:

[RequireHttps]
public ActionResult Login()
{
   return View();
}

虽然,命令的参数是值得注意的,因为这里所说的 。



Answer 2:

MVCFutures有一个“RequireSSL”属性。

(感谢亚当的指出了这一点在你的博客帖子更新)

只要将它应用到你的操作方法,以“重定向=真正的”如果你想要一个http://请求自动变成https://开头:

    [RequireSsl(Redirect = true)]

参见: 在生产ASP.NET MVC RequireHttps只有



Answer 3:

作为Amadiere写道 ,[RequireHttps]在MVC 2 进入 HTTPS的伟大工程。 但是,如果你只希望像你说的使用HTTPS对于一些网页,MVC 2不给你任何的爱-一旦切换用户HTTPS他们被困在那里,直到手动重定向他们。

我使用的方法是使用另一个自定义属性,[ExitHttpsIfNotRequired。 当连接到控制器或动作,这将重定向到HTTP,如果:

  1. 该请求是HTTPS
  2. 的[RequireHttps]属性未施加到所述动作(或控制器)
  3. 请求是一个GET(重定向POST会导致各种各样的麻烦)。

这是一个有点过大,张贴在这里,但你可以看到这里的代码加上一些额外的细节。



Answer 4:

下面是从丹Wahlin最近的文章上这样的:

http://weblogs.asp.net/dwahlin/archive/2009/08/25/requiring-ssl-for-asp-net-mvc-controllers.aspx

他用一个ActionFilter属性。



Answer 5:

有些ActionLink的扩展: http://www.squaredroot.com/post/2008/06/11/MVC-and-SSL.aspx或者重定向到https的控制器action属性:// http://forums.asp.net /p/1260198/2358380.aspx#2358380



Answer 6:

对于那些谁不属于面向属性的开发方法风扇,这里是一段代码,可以帮助:

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);
    }
}

有几个原因,以避免属性和其中之一是,如果你想看看你将不得不跳过在溶液中的所有控制器的所有安全网页的清单。



Answer 7:

我去翻过这个问题,希望我的解决方案可以帮助别人。

我们得到了几个问题: - 我们需要保护的具体行动,例如“登录”,在“帐户”。 我们可以使用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://网址。 另外,我已经把一个领域,使我们能够确定我们是否应该要求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() { }
}

现在,在每个cpntroller /动作,你想要求SSL - 刚刚成立与ConnectionProtocol.Https此属性。

现在,让我们移至网址:我们得到了与URL路由引擎几个问题。 你可以阅读更多关于他们http://blog.stevensanderson.com/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/ 。 在这篇文章中提出的解决方案是theoreticly不错,但老了,不喜欢计算策略。

我的解决方案如下:创建基本的“路”类的子类:

公共类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
}

这种“途径”类的版本将创建绝对URL。 这里的技巧,其次是博客文章的作者建议,就是用DataToken指定(末尾:)例子)的方案。

现在,如果我们将生成一个URL,例如用于路线“帐户/登录”我们会得到“/ 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";
    }


Answer 8:

这里有一个博客帖子巴勃罗·M. Cibrano从2009年1月,其收集了几个技术,包括一个HTTP模块和扩展方法。



Answer 9:

这里有一个由亚当·萨尔沃博客文章使用一个ActionFilter。



Answer 10:

这不一定是MVC具体,但这种解决方案并不两个ASP.NET WebForms和MVC的工作:

http://www.codeproject.com/KB/web-security/WebPageSecurity_v2.aspx

我已经使用了好几年,并愿意通过web.config文件的关注点分离和管理。



Answer 11:

MVC 6(ASP.NET核心1.0)正在与Startup.cs略有不同。

要使用RequireHttpsAttribute(如中提到的答案在所有网页上的Amadiere),你可以在Startup.cs添加此而不是使用每个控制器上的属性风格(或代替创建所有的控制器从继承BaseController)。

Startup.cs -注册过滤器:

public void ConfigureServices(IServiceCollection services)
{
    // TODO: Register other services

    services.AddMvc(options =>
    {
        options.Filters.Add(typeof(RequireHttpsAttribute));
    });
}

有关设计决定了上述方法的详细信息,请参阅有关类似的问题,我的回答如何从由RequireHttpsAttribute正在处理排除本地主机的请求 。



文章来源: SSL pages under ASP.NET MVC