【问题标题】:ASP.NET MVC: How to automatically disable [RequireHttps] on localhost?ASP.NET MVC:如何在 localhost 上自动禁用 [RequireHttps]?
【发布时间】:2011-04-07 09:22:11
【问题描述】:

我希望我的登录页面仅是 SSL:

    [RequireHttps]
    public ActionResult Login()
    {
        if (Helper.LoggedIn)
        {
            Response.Redirect("/account/stats");
        }

        return View();
    }

但是当我开发和调试我的应用程序时,显然它在 localhost 上不起作用。我不想使用带有 SSL 证书的 IIS 7,如何自动禁用 RequireHttps 属性?

更新

根据 StackOverflow 用户和 ASP.NET MVC 2 源代码提供的信息,我创建了以下解决问题的类。

public class RequireSSLAttribute : FilterAttribute, IAuthorizationFilter
{
    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)
    {
        if (filterContext.HttpContext.Request.Url.Host.Contains("localhost")) return;

        if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("The requested resource can only be accessed via SSL");
        }

        string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
        filterContext.Result = new RedirectResult(url);
    }
}

它是这样使用的:

[RequireSSL]
public ActionResult Login()
{
    if (Helper.LoggedIn)
    {
        Response.Redirect("/account/stats");
    }

    return View();
}

【问题讨论】:

  • 如果你在 Stack Overflow 上搜索“RequireHttps”,这个问题已经被问了好几次了,所以有很多关于解决方案的信息。这是一个很好的问题,但是我还没有使用过该属性,但我可以立即看到它是一个问题。
  • 你是对的。问题已经解决,我用对我有帮助的课程更新了我的主要帖子。

标签: asp.net-mvc debugging iis ssl localhost


【解决方案1】:

最简单的方法是从 RequireHttps 派生一个新属性并覆盖 HandleNonHttpsRequest

protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
        {
            if (!filterContext.HttpContext.Request.Url.Host.Contains("localhost"))
            {
                base.HandleNonHttpsRequest(filterContext);
            }
        }

HandleNonHttpsRequest 是引发异常的方法,如果主机是 localhost,我们在这里所做的只是不调用它(正如 Jeff 在他的评论中所说,您可以将其扩展到测试环境或实际上任何其他您想要的异常)。

【讨论】:

  • 此方法可以修改为在测试环境中也不需要 HTTPS。
  • 我使用您的代码和 MVC 的源代码创建了一个解决方案。谢谢!
  • 在阅读thisthis 作为安全措施时,我们应该在FilterConfig 中添加filters.Add(new RequireSSLAttribute ()); 吗?
  • @stom 问题特别是关于如何禁用 localhost 的属性,但如果我们谈论保护您的应用程序作为一个整体,是的,您应该将它添加到您的全局过滤器中,您应该设置 @ 987654326@ 也是标头。
  • 您可以使用 filterContext.HttpContext.Request.IsLocal 而不是搜索字符串
【解决方案2】:
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) {

        if (!HttpContext.Current.IsDebuggingEnabled) {
            filters.Add(new RequireHttpsAttribute());
        }
    }

【讨论】:

  • 添加一些关于该代码放置位置的信息会更有帮助,以帮助那些不熟悉 ASP.NET MVC 的人。
  • 在我当前的 MVC 项目中,App_Start 文件夹中有一个名为 FilterConfig.cs 的默认文件。在那里添加它。
【解决方案3】:
#if (!DEBUG)
[RequireHttps]
#endif
public ActionResult Login()
{
    if (Helper.LoggedIn)
    {
        Response.Redirect("/account/stats");
    }

    return View();
}

【讨论】:

  • 我也想过这个。但这意味着我必须为每个 RequireHttps 属性添加#if DEBUG。
  • 啊,我以为只有一次。那么其他的建议更好。
【解决方案4】:

您可以将此要求封装在派生属性中:

class RequireHttpsNonDebugAttribute : RequireHttpsAttribute {
    public override void HandleNonHttpsRequest(AuthorizationContext ctx) {
        #if (!DEBUG)
        base.HandleNonHttpsRequest(ctx);
        #endif
    }
}

【讨论】:

    【解决方案5】:

    MVC 6(ASP.NET Core 1.0):

    正确的解决方案是使用 env.IsProduction() 或 env.IsDevelopment()。

    例子:

    Startup.cs - 带有自定义过滤器的 AddMvc:

    public void ConfigureServices(IServiceCollection services)
    {
        // TODO: Register other services
    
        services.AddMvc(options =>
        {
            options.Filters.Add(typeof(RequireHttpsInProductionAttribute));
        });
    }
    

    自定义过滤器继承自RequireHttpsAttribute

    public class RequireHttpsInProductionAttribute : RequireHttpsAttribute
    {
        private bool IsProduction { get; }
    
        public RequireHttpsInProductionAttribute(IHostingEnvironment environment)
        {
            if (environment == null)
                throw new ArgumentNullException(nameof(environment));
            this.IsProduction = environment.IsProduction(); 
        }
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (this.IsProduction)
                base.OnAuthorization(filterContext);
        }
        protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
        {
            if(this.IsProduction)
                base.HandleNonHttpsRequest(filterContext);
        }
    }
    

    解释设计决策:

    1. 使用环境 IsProduction() 或 IsDevelopment(),例如 “#如果调试”。有时我们在测试服务器上以 DEBUG 模式发布/发布,并且不想禁用此安全要求。这只需要在 localhost/development 中禁用(因为我们懒得在 IIS Express 或我们在本地使用的任何东西中设置 localhost SSL)。
    2. 在 Startup.cs 中使用过滤器进行全局设置(因为我们希望它适用于任何地方)。 Startup 应负责注册和设置所有全局规则。如果您的公司雇用了一位新开发人员,她会希望在 Startup.cs 中找到全局设置。
    3. 使用 RequireHttpsAttribute 逻辑,因为它已被证明(由 Microsoft)。我们唯一要改变的是何时应用逻辑(生产)和何时不应用逻辑(开发/本地主机)。切勿使用“http://”和“https://”之类的“神奇”字符串,因为可以通过重复使用为提供相同逻辑而创建的 Microsoft 组件来避免这种情况。

    以上我会考虑“适当”的解决方案。

    注意:

    作为替代方法,我们可以创建一个“类 BaseController : Controller”,并让我们所有的控制器都继承自“BaseController”(而不是 Controller)。那么我们只需要设置属性1全局的地方(并且不需要在Startup.cs中注册过滤器)。

    有些人更喜欢属性样式。请注意,这将消除设计决策 #2 的好处。

    使用示例:

    [RequireHttpsInProductionAttribute]
    public class BaseController : Controller
    {
        // Maybe you have other shared controller logic..
    }
    
    public class HomeController : BaseController
    {
        // Add endpoints (GET / POST) for Home controller
    }
    

    【讨论】:

      猜你喜欢
      • 2010-12-07
      • 1970-01-01
      • 1970-01-01
      • 2010-12-11
      • 2015-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多