远程需要HTTPS MVC 5

我有以下属性,以确保远程站点页面以https模式打开。

public class RemoteRequireHttpsAttribute : RequireHttpsAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentException("Filter Context"); } if (filterContext != null && filterContext.HttpContext != null) { if (filterContext.HttpContext.Request.IsLocal) { return; } else { string val = ConfigurationManager.AppSettings["RequireSSL"].Trim(); bool requireSsl = bool.Parse(val); if (!requireSsl) { return; } } } base.OnAuthorization(filterContext); } } 

本地开发现在正常工作,因为我不希望它以https模式打开。

开发站点以https模式打开页面 – 此处没有问题(单个节点)。

我正在设置的生产(负载平衡 – 2个节点)站点在哪里给我跟随错误。 请注意,dev和prod站点具有相同的setings和web.config

页面未正确重定向

Firefox检测到服务器正在以永远不会完成的方式重定向此地址的请求。

有时可能会因禁用或拒绝接受Cookie而导致此问题。

Dev site url就像http://dev.datalab.something.org

Prod网站url就像http://datalab.something.org

这是电话

 [RemoteRequireHttps] public ActionResult Index(string returnUrl, string error) 

我在这里缺少什么?

更新1:我的管理员已确认已在lad balancer evel上设置了SSL终止。 我查看了iis站点设置,但我没有看到https绑定。 我只看到http绑定。 他是否还需要设置https绑定?

更新2: @AlexeiLevenkov指出我正确的方向, 这篇文章有我使用的代码,它正在工作。 将代码移动到单独的答案中。

您的站点是支持SSL终止的负载均衡器 – 因此,无论用户看到什么,所有到您站点的传入流量都是HTTP。 这会导致您的代码始终尝试重定向到HTTPS版本,从而无限循环。

修复选项:

  • 通常,SSL终止的负载均衡器将通过自定义标头转发原始IP /协议。 x-forwarded-proto和x-forwarded-for是用于此目的的常见问题。 如果使用这些标头或需要一些其他配置,您可能需要与网络管理员核实
  • 或者,您可以关闭SSL终止,但它会给您的服务器带来额外的负载。
  • 还可以将负载均衡器配置为使用与传入请求相同的协议与服务器通信。

如何调查此类问题:

  • 查看http调试器(如Fiddler),了解您是否在循环中获得30x重定向请求。 如果没有重定向 – 可能代码错误。
  • 如果您看到重复重定向,则可能意味着站点看不到实际的请求信息 – 可能是协议,路径cookie丢失。
  • 要继续调查,请查看用户和服务器之间的设备(CDN,代理,负载均衡器……) – 每个设备都有机会丢失一些日期或转换协议。

并不是说我反对编写好的自定义属性,或许在web.config中执行重定向并使用可用于web.config的转换来将生产部署中的启用值从false更改为true是没有意义的吗?

            

将修复程序移动到@AlexeiLevenkov所指出的单独答案中。

 public class RemoteRequireHttpsAttribute : RequireHttpsAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentException("Filter Context"); } if(filterContext.HttpContext != null) { if (filterContext.HttpContext.Request.IsSecureConnection) { return; } var currentUrl = filterContext.HttpContext.Request.Url; if (currentUrl.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.CurrentCultureIgnoreCase)) { return; } if (string.Equals(filterContext.HttpContext.Request.Headers["X-Forwarded-Proto"], "https", StringComparison.InvariantCultureIgnoreCase)) { return; } if (filterContext.HttpContext.Request.IsLocal) { return; } var val = ConfigurationManager.AppSettings["RequireSSL"].Trim(); var requireSsl = bool.Parse(val); if (!requireSsl) { return; } } base.OnAuthorization(filterContext); } } 

我也更新了ExitHttps属性。 这有类似的问题……

 public class ExitHttpsAttribute : FilterAttribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentException("Filter Context"); } if (filterContext.HttpContext == null) { return; } var isSecure = filterContext.HttpContext.Request.IsSecureConnection; var currentUrl = filterContext.HttpContext.Request.Url; if (!isSecure && currentUrl.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.CurrentCultureIgnoreCase)) { isSecure = true; } if (!isSecure && string.Equals(filterContext.HttpContext.Request.Headers["X-Forwarded-Proto"], "https", StringComparison.InvariantCultureIgnoreCase)) { isSecure = true; } if (isSecure) { //in these cases keep https // abort if a [RequireHttps] attribute is applied to controller or action if (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof (RequireHttpsAttribute), true).Length > 0) { isSecure = false; } if (isSecure && filterContext.ActionDescriptor.GetCustomAttributes(typeof (RequireHttpsAttribute), true).Length > 0) { isSecure = false; } // abort if a [RetainHttps] attribute is applied to controller or action if (isSecure && filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof (RetainHttpsAttribute), true).Length > 0) { isSecure = false; } if (isSecure && filterContext.ActionDescriptor.GetCustomAttributes(typeof (RetainHttpsAttribute), true).Length > 0) { isSecure = false; } // abort if it's not a GET request - we don't want to be redirecting on a form post if (isSecure && !String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { isSecure = false; } } if (!isSecure) { return; } // redirect to HTTP var url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; filterContext.Result = new RedirectResult(url); } }