ASP.NET MVC:如何在 localhost 上自动禁用 [RequireHttps]?

Posted

技术标签:

【中文标题】ASP.NET MVC:如何在 localhost 上自动禁用 [RequireHttps]?【英文标题】:ASP.NET MVC: How to automatically disable [RequireHttps] on localhost? 【发布时间】: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 属性?

更新

根据 *** 用户和 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”,这个问题已经被问了好几次了,所以有很多关于解决方案的信息。这是一个很好的问题,但是我还没有使用过该属性,但我可以立即看到它是一个问题。 你是对的。问题已经解决,我用对我有帮助的课程更新了我的主要帖子。 【参考方案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 的源代码创建了一个解决方案。谢谢! 在阅读this 和this 作为安全措施时,我们应该在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);
    

解释设计决策:

    使用环境 IsProduction() 或 IsDevelopment(),例如 “#如果调试”。有时我们在测试服务器上以 DEBUG 模式发布/发布,并且不想禁用此安全要求。这只需要在 localhost/development 中禁用(因为我们懒得在 IIS Express 或我们在本地使用的任何东西中设置 localhost SSL)。 在 Startup.cs 中使用过滤器进行全局设置(因为我们希望它适用于任何地方)。 Startup 应负责注册和设置所有全局规则。如果您的公司雇用了一位新开发人员,她会希望在 Startup.cs 中找到全局设置。 使用 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

【讨论】:

以上是关于ASP.NET MVC:如何在 localhost 上自动禁用 [RequireHttps]?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 asp.net mvc 3 项目中路由 .aspx 页面?

如何接受数组作为 ASP.NET MVC 控制器操作参数?

如何在 ASP.Net MVC - 5 应用程序中显示版本号并自动递增

vs2012发布asp.net mvc4的网站到iis上,发布后在访问数据库的地方出错?

ASP.Net mvc2 url 格式问题

如何将文件发布到 asp.net mvc 应用程序? [复制]