【问题标题】:Moving between HTTP and HTTPS in ASP.NET MVC在 ASP.NET MVC 中的 HTTP 和 HTTPS 之间移动
【发布时间】:2010-11-25 13:59:25
【问题描述】:

所以我找到了 [RequiresHttps] 属性,但是一旦你进入 https,你就会卡在那里,所以尝试并能够对单个 url(和方案)进行操作,我发现我已经结束了对于不使用 [RequireHttps] 的操作,必须创建自己的 ExtendedController 才能恢复为 http。

只是想知道我正在做的事情是否可以,或者是否有更好的方法?

public class ExtendedController : Controller
{
    protected virtual void HandleHttpRequest(AuthorizationContext filterContext)
    {
        if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Cannot post between https and http.");
        }
        string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
        filterContext.Result = new RedirectResult(url);
    }

    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        object[] attributes = filterContext.ActionDescriptor.GetCustomAttributes(true);
        if (!attributes.Any(a => a is RequireHttpsAttribute))
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            if (filterContext.HttpContext.Request.IsSecureConnection)
            {
                this.HandleHttpRequest(filterContext);
            }
        }
    }
}

【问题讨论】:

  • 我刚刚意识到的一件事是我还应该检查 filterContext.IsChildAction - 我想知道在子操作上使用 RequiresHttp 是否有可能遇到相同的问题。似乎在路由端而不是控制器上可能需要更完整的解决方案。

标签: asp.net-mvc


【解决方案1】:

您所拥有的在语法上是正确的,但是建议创建一个新的 Action 过滤器,该过滤器继承自默认的 RequireHttpsAttribute 并采用参数在 http 和 https 之间切换。

public class RequireHttpsAttribute : System.Web.Mvc.RequireHttpsAttribute
{
    public bool RequireSecure = false;

    public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)

    {
        if (RequireSecure)
        {
            base.OnAuthorization(filterContext);
        }
        else
        {
            // non secure requested
            if (filterContext.HttpContext.Request.IsSecureConnection)
            {
                HandleNonHttpRequest(filterContext);
            }
        }
    }

    protected virtual void HandleNonHttpRequest(AuthorizationContext filterContext)
    {
        if (String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            // redirect to HTTP version of page
            string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
            filterContext.Result = new RedirectResult(url);
        }
    } 
}

然后,在您将使用的操作方法或控制器上:

[RequireHttps (RequireSecure = true)]

...

[RequireHttps (RequireSecure = false)]

【讨论】:

  • 需要注意的是这默认为非安全的“public bool RequireSecure = false;”而 System.Web.Mvc.RequireHttpsAttribute 需要 HTTPS。如果你想并行 System.Web.Mvc.RequireHttpsAttribute 只需将默认设置为“true”。
【解决方案2】:

使其更易于管理。此解决方案假定您的大多数 Web 应用程序使用 HTTP 方案。

  1. 创建新的操作过滤器 RequiresHttp(如果 NeedSsl 属性未明确应用于操作或控制器,则使用 HTTP),

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase req = filterContext.HttpContext.Request;
        HttpResponseBase res = filterContext.HttpContext.Response;
    
        bool needSsl = filterContext.ActionDescriptor.IsDefined(typeof(NeedSslAttribute), true)
                        || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(NeedSslAttribute), true);
    
    
        if (needSsl && !req.IsSecureConnection) //https: secure
        {
            var builder = new UriBuilder(req.Url)
            {
                Scheme = Uri.UriSchemeHttps,
                Port = 444
            };
            res.Redirect(builder.Uri.ToString());
        }
        else if (!needSsl && req.IsSecureConnection) //http: non secure
        {
            var builder = new UriBuilder(req.Url)
            {
                Scheme = Uri.UriSchemeHttp,
                Port = 8081
            };
            res.Redirect(builder.Uri.ToString());
        }
        base.OnActionExecuting(filterContext);
    }
    
  2. 以及新的空白属性NeedSSL(用于指示目的)

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class NeedSslAttribute : Attribute { }
    
  3. 在 Global.aspx.cs 中应用 RequiresHttp 作为全局操作过滤器

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new RequiresHttp());
    }
    
  4. 现在在你想使用 HTTPS 方案的控制器和操作上应用应用 NeedSslAttribute

    [NeedSsl]
    [AllowAnonymous]
    public ActionResult LogOn()
    

此代码并不完美,因为动作过滤器RequiresHttp 执行多项工作,即检查NeedSsl 属性并应用HTTPHTTPS 方案。如果我们可以使用两个动作过滤器RequiresHTTPRequiresHTTPS 会更好。

现在,如果将RequiresHTTP 设置为全局过滤器并将RequiresHTTPS 过滤器应用于特定操作,并且特定RequiresHTTPS 过滤器将优先考虑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-20
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 2015-08-04
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    相关资源
    最近更新 更多