【问题标题】:Forcing http or https using a route or other method?使用路由或其他方法强制使用 http 或 https?
【发布时间】:2014-03-14 16:54:22
【问题描述】:

我有一个标准网站

拥有所有公共页面的www.example.com

但用户登录后,所有页面都处于安全模式:https://www.example.com

我要强制相关页面只有httphttps

http 的角度来看,我不希望 https://www.example.com/about/Google 那样工作惩罚重复内容的网站。

从登录的角度来看,我不想要

http://www.example.com/signin/

出于明显的安全原因而工作。

最好的方法是什么?

访问错误的版本会导致永久 301 重定向

【问题讨论】:

  • 你永远不知道你的运气戴夫 :)
  • 幸运和奖励都值得赞赏,戴尔! PS,你用的是哪个MVC框架?我想用版本重新标记你的帖子。

标签: asp.net asp.net-mvc routes asp.net-mvc-5


【解决方案1】:

我将这个动作过滤器放在一起,以了解可以做什么

public class RequireNonSSLAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
       if (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Length > 0) return;
       if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Length > 0) return;
       if (!filterContext.IsChildAction)  return;

        // else

        UriBuilder uriBuilder = new UriBuilder(Request.Url); 

        //change the scheme 
        uriBuilder.Scheme = "http"; 
        uriBuilder.Port = 80; 

        filterContext.Result = this.RedirectPermanent(uriBuilder.Uri.AbsoluteUri); 


     base.OnActionExecuting(filterContext);
    }   
}

这个想法只是在没有请求但使用 SSL 时重写 url。我暂时无法测试它。

【讨论】:

  • 我真的很喜欢为它使用自定义属性的想法,唯一的问题是它需要是 RedirectPermanent。并且 RequireHttps 必须扩展为使用 301 重定向,如 stackoverflow.com/questions/9624659/…
  • @ThomasStiegler 使用filterContext.Result = this.RedirectPermanent(uriBuilder.Uri.AbsoluteUri);
【解决方案2】:

你可以使用上面的[RequireHttps]属性,你需要只使用Https的Action方法。如果这以某种方式限制了您,您可以创建自定义属性。

【讨论】:

  • 我认为你没有抓住重点。一旦你使用RequireHttps,所有使用的页面都将使用 ssl。您还没有向 OP 展示从后来点击的页面中删除 SSL 加密的方法。
  • 是的,我真的错过了,谢谢。明天我将在我的回答中分享包括这两种情况的更新。
【解决方案3】:

我使用以下内容。 RevertToHttpAttribute 是您特别要求的,而 OptionalHttpRemoteRequireHttpsAttribute 允许例外,这允许冲突的属性自行解决。

我想我还将整合来自Dave A's 答案的 IsChildAction 行,因为这也简化了事情。

/// <summary>
/// Represents an attribute that attempts a secured HTTPS request to be re-sent over HTTP.
/// </summary>
public class RevertToHttpAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        // abort if it's not a secure connection
        if (!filterContext.HttpContext.Request.IsSecureConnection) return;

        // abort if it's not a GET request - we don't want to be redirecting on a form post
        if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) return;

        var attributes = new[] { typeof(RequireHttpsAttribute), typeof(OptionalHttpsAttribute) };

        foreach (var attribute in attributes)
        {
            // abort if attribute is applied to controller or action
            if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(attribute, true)) return;
            if (filterContext.ActionDescriptor.IsDefined(attribute, true)) return;
        }

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

/// <summary>
/// Only requires HTTPS when not running locally
/// </summary>
public class RemoteRequireHttpsAttribute : RequireHttpsAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");
        if (filterContext.HttpContext != null && filterContext.HttpContext.Request.IsLocal)
            return;
        if (filterContext.ActionDescriptor.IsDefined(typeof(OptionalHttpsAttribute), true))
            return;

        base.OnAuthorization(filterContext);
    }
}

/// <summary>
/// Represents an attribute that prevents an HTTP/HTTPS request to be re-sent over it's cohort.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class OptionalHttpsAttribute : Attribute
{
}

【讨论】:

  • +1 这个解决方案效果很好。我选择操作过滤器的原因是因为您还可以选择全局注册它。由于操作过滤器总是在身份验证过滤器之后执行,因此上下文总是会知道用户是否打算使用 SSL。
【解决方案4】:

建议两个非常简单的解决方案:

  1. 无论用户是否登录,都使用 HTTPS。

  1. 为公共站点创建一个 www.whatever.com 子域,为登录的用户站点创建一个secure.whatever.com。 Google 不会将子域等同起来,因此不会将您的内容视为重复内容。

【讨论】:

  • 这将起作用并且省去了创建进出安全模式的逻辑的麻烦。但是处理子域有它自己的麻烦;如果您使用子域中的 web-api,您将遇到跨域问题、维护子域路由等
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-05
  • 2011-03-19
  • 2011-06-11
  • 2016-04-27
  • 2014-01-22
  • 1970-01-01
相关资源
最近更新 更多