【问题标题】:MVC RequireHttps and redirect if not httpsMVC RequireHttps 如果不是 https 则重定向
【发布时间】:2011-07-23 18:21:21
【问题描述】:

我已经阅读了许多关于 ASP.NET MVC [RequireHttps] 的问题 - 但找不到这个问题的答案:

如果不是以https开头,如何使[RequireHttps]属性将url切换为https?

我有这个代码:

public ActionResult DoSomething()
{
    return View("AnotherAction");
}

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

但我收到一条错误消息:“请求的资源只能通过 SSL 访问。”

MVC 期货项目有一个类似的属性[RequireSsl(Redirect = true)]。但是现在已经过时了...... MVC 2 中的等价物是什么?

当有人输入 URL http://example.com/home/dosomething 或 URL http://example.com/home/anotheraction 时,我需要将他们自动重定向到 URL https://example.com/home/anotheraction

编辑这是事件的顺序:

从另一个网站调用 URL http://example.com/home/dosomething。他们将用户重定向到这个 url(使用 response.redirect 或类似的)。

DoSomething() 然后尝试返回AnotherAction(),但失败并显示错误消息“请求的资源只能通过 SSL 访问。”

【问题讨论】:

  • 你可以编写一个自定义属性来做到这一点。

标签: c# asp.net-mvc-2 ssl requirehttps


【解决方案1】:

Http HEAD 请求似乎没有被重定向。在查看我们的错误日志时,我们看到很多这样的消息,谷歌搜索在这里,但在查看更多细节后,他们有一些有趣的“功能”

  • Request_method:HEAD
  • 用户代理:curl/7.35.0

换句话说,所有失败的尝试都不是面向客户的......

(100% 归功于 @arserbin3 的评论让我意识到他们都是 HEAD 请求)

【讨论】:

    【解决方案2】:

    [mvc 4] 简短回答:

    protected void Application_BeginRequest(Object source, EventArgs e)
    {
      if (!Context.Request.IsSecureConnection)
      {
          Response.Redirect(Request.Url.AbsoluteUri.Replace("http://", "https://"));
      }
    }
    

    更长的答案:
    要从 http 移动到 https,您不能在第一个数据包之后发送重定向到 https,
    因此,您需要使用 Application_BeginRequest 捕获数据包,
    从 Global.asax 添加该函数,它将覆盖默认值,
    代码应该是这样的(类级别的 Global.asax):

    protected void Application_BeginRequest(Object source, EventArgs e)
    {
      if (!Context.Request.IsSecureConnection && 
          !Request.Url.Host.Contains("localhost") && 
          Request.Url.AbsolutePath.Contains("SGAccount/Login"))
      {
          Response.Redirect(Request.Url.AbsoluteUri.Replace("http://", "https://"));
      }
    }
    

    我强烈建议设置断点并检查 Request.Url 对象是否有任何与 url 相关的需求。
    或访问 msdn page 对 request.url absoluteuri vs originalstring 感到困惑?
    我也是,你可以去dotnetperls 举例。
    此功能使您能够在 localhost 上进行开发并按原样部署您的代码。
    现在,对于您想要进行 https 重定向的每个页面,您需要在 if 条件中指定它。
    要从 https 移动到 http,您可以像这样使用常规 Response.Redirect:

    if (Request.Url.Scheme.Contains("https"))
    {
        Response.Redirect(string.Format("http://{0}", Request.Url.Authority), true);
    }
    

    请注意,这也支持在本地主机上开发时使用相同的代码,而不是在添加 https 之前中断原始过程。

    我还建议考虑实施一些返回 url 约定(如果尚未实施),在这种情况下你应该这样做:

    if (Request.Url.Scheme.Contains("https"))
    {
        Response.Redirect(string.Format("http://{0}{1}", Request.Url.Authority, returnUrl), true);
    }
    

    这将重定向到登录后请求的页面。

    当然,您应该保护显示用户数据、注册、登录等的每个页面。

    【讨论】:

    • 寻找字符串“localhost”可能并不总是有效 - 它可以被重命名。请参阅这个类似的主题,我的回答是使用 Startup.cs (MVC 6) 中的内置 RequireHttpsAttribute 来解释 how to handle HTTPS for production only
    • 感谢您指出代码应该放在“global.asax”中。
    【解决方案3】:

    MVC4 现在会重定向

    但不是你所期望的。

    http://www.example.com:8080/alpha/bravo/charlie?q=quux 将客户端的浏览器重定向到 https://www.example.com/alpha/bravo/charlie?q=quux

    请注意缺少端口号。

    http://aspnetwebstack.codeplex.com/SourceControl/latest#test/System.Web.Mvc.Test/Test/RequireHttpsAttributeTest.cs 代码测试 [事实] 公共无效 OnAuthorizationRedirectsIfRequestIsNotSecureAndMethodIsGet()

    确认这是所需的行为。

    如果您想编写一个包含 PORT 的自定义属性...您可以将代码基于:

    http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/RequireHttpsAttribute.cs

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public class RequireHttpsAttribute : FilterAttribute, IAuthorizationFilter
    {
        public RequireHttpsAttribute()
            : this(permanent: false)
        {
        }
    
        /// <summary>
        /// Initializes a new instance of the <see cref="RequireHttpsAttribute"/> class.
        /// </summary>
        /// <param name="permanent">Whether the redirect to HTTPS should be a permanent redirect.</param>
        public RequireHttpsAttribute(bool permanent)
        {
            this.Permanent = permanent;
        }
    
        /// <summary>
        /// Gets a value indicating whether the redirect to HTTPS should be a permanent redirect.
        /// </summary>
        public bool Permanent { get; private set; }
    
        public virtual void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
    
            if (!filterContext.HttpContext.Request.IsSecureConnection)
            {
                HandleNonHttpsRequest(filterContext);
            }
        }
    
        protected virtual 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(MvcResources.RequireHttpsAttribute_MustUseSsl);
            }
    
            // redirect to HTTPS version of page
            string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
            filterContext.Result = new RedirectResult(url, this.Permanent);
        }
    }
    

    【讨论】:

      【解决方案4】:

      为了补充已经给出的答案,这是来自 HandleNonHttpsRequest 的 MVC 5 实现的代码

      protected virtual void HandleNonHttpsRequest(AuthorizationContext filterContext)
      {
          // only redirect for GET requests, otherwise the browser might not propagate the verb and request
          // body correctly.
          ...
      }
      

      【讨论】:

        【解决方案5】:

        RequiresHttps 属性会自动尝试重定向到https://your-url。我在使用该属性的网站上验证了这种行为,并查看了 Reflector 中的代码:

        protected virtual void HandleNonHttpsRequest(AuthorizationContext filterContext)
        {
            if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException(MvcResources.RequireHttpsAttribute_MustUseSsl);
            }
            string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
            filterContext.Result = new RedirectResult(url);
        }
        

        您确定您的网站设置为接受安全连接吗?如果您尝试直接浏览到https://your-url,会发生什么情况?

        【讨论】:

        • 实际上正如您上面的代码所示,它只重定向 GET 请求。如果 POST(或 HEAD 等)请求进来,它只会抛出异常。一个重要的区别
        • 另一个后果是任何具有 [RequireHttps] 并通过 GET 访问的控制器操作也应该具有 [HttpGet] 属性,以防止有时在其 GET 之前/而不是其 GET 发送的 HEAD 请求上出现异常对应。
        猜你喜欢
        • 2017-09-15
        • 1970-01-01
        • 2017-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-07
        相关资源
        最近更新 更多