C# 远程要求HTTPS MVC 5

C# 远程要求HTTPS MVC 5,c#,asp.net-mvc-5,C#,Asp.net Mvc 5,我有以下属性来确保远程站点页面以https模式打开 public class RemoteRequireHttpsAttribute : RequireHttpsAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) {

我有以下属性来确保远程站点页面以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站点具有相同的设置和web.config

页面未正确重定向

Firefox检测到服务器正在以一种永远无法完成的方式重定向对此地址的请求

此问题有时可能是由于禁用或拒绝接受Cookie造成的

开发人员站点url类似于

产品站点url类似于

这是电话

[RemoteRequireHttps]
public ActionResult Index(string returnUrl, string error)
我错过了什么

更新1:我的管理员已确认已在lad平衡器级别设置SSL终止。我查看了iis站点设置,没有看到https绑定。我只看到http绑定。他也需要设置https绑定吗


更新2:@AlexeiLevenkov为我指明了正确的方向,并拥有我使用的代码,它正在工作。将代码移到单独的答案中

我并不反对编写漂亮的自定义属性,也许在web.config中执行重定向并使用web.config可用的转换将下面的启用值从false更改为true以用于生产部署,这样做没有意义吗

<rewrite>
  <rules>
    <rule name="SSL_ENABLED" enabled="false" stopProcessing="true">
      <match url="(.*)" />
      <conditions>
        <add input="{HTTPS}" pattern="^OFF$" />
      </conditions>
      <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
    </rule>
  </rules>
</rewrite>

我并不反对编写漂亮的自定义属性,也许在web.config中执行重定向并使用web.config可用的转换将下面的启用值从false更改为true以用于生产部署,这样做没有意义吗

<rewrite>
  <rules>
    <rule name="SSL_ENABLED" enabled="false" stopProcessing="true">
      <match url="(.*)" />
      <conditions>
        <add input="{HTTPS}" pattern="^OFF$" />
      </conditions>
      <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
    </rule>
  </rules>
</rewrite>

您的站点位于执行SSL终止的负载平衡器之后——因此,无论用户看到什么,到您站点的所有传入流量都是HTTP。这会导致您的代码总是尝试重定向到HTTPS版本,从而导致无限循环

修复选项:

通常,执行SSL终止的负载平衡器将通过自定义头转发原始IP/协议。和x-forwarded-for是用于此目的的常用设备。您可能需要与网络管理员确认是否使用了这些头文件或需要一些额外的配置 或者,您可以关闭SSL终止,但这会给服务器带来额外的负载。 还可以将负载平衡器配置为使用与传入请求相同的协议与服务器通信。 如何调查此类问题:

查看http调试器(如Fiddler),看看是否在循环中收到30倍的重定向请求。如果没有重定向-可能代码错误。 若你们看到重复的重定向,这可能意味着站点并没有看到实际的请求信息——可能是协议、路径cookie丢失。 要继续调查,请查看用户和服务器CDN、代理、负载平衡器等之间的设备-每个人都有很好的机会失去一些日期或转换协议。
您的站点位于执行SSL终止的负载平衡器之后——因此,无论用户看到什么,到您站点的所有传入流量都是HTTP。这会导致您的代码总是尝试重定向到HTTPS版本,从而导致无限循环

修复选项:

通常,执行SSL终止的负载平衡器将通过自定义头转发原始IP/协议。和x-forwarded-for是用于此目的的常用设备。您可能需要与网络管理员确认是否使用了这些头文件或需要一些额外的配置 或者,您可以关闭SSL终止,但这会给服务器带来额外的负载。 还可以将负载平衡器配置为使用与传入请求相同的协议与服务器通信。 如何调查此类问题:

查看http调试器(如Fiddler),看看是否在循环中收到30倍的重定向请求。如果没有重定向-可能代码错误。 若你们看到重复的重定向,这可能意味着站点并没有看到实际的请求信息——可能是协议、路径cookie丢失。 要继续调查,请查看用户和服务器CDN、代理、负载平衡器等之间的设备-每个人都有很好的机会失去一些日期或转换协议。
如@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);
        }
    }

如@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);
        }
    }

看起来你没有将用户重定向回HTTPS连接,你只是在拒绝访问?你有一种无限循环,你的页面被来回重定向。使用浏览器的调试工具确定它在哪些页面之间跳转,然后检查这些页面的配置/代码。RemoteRequireHttps继承自RequireHttpAttribute。这将执行重定向@梅森,我有

在dev和prod站点上使用相同的代码。开发人员站点以https模式显示页面,效果很好。没有重定向问题。此操作只应用了一个属性。请查看IIS日志以了解传入的请求。。。我很有可能它们都是HTTP,因为在服务器之前的某个地方。@learning…这里的大部分答案是-prod是负载平衡的。当您检查负载平衡器是否配置为执行SSL终止时,其余部分将被清除。改为阅读标题,你的生活会很好。看起来你并不是在将用户重定向回HTTPS连接,你只是在拒绝访问?你有一种无限循环,你的页面被来回重定向。使用浏览器的调试工具确定它在哪些页面之间跳转,然后检查这些页面的配置/代码。RemoteRequireHttps继承自RequireHttpAttribute。这将执行重定向@mason我在dev和prod站点上都有相同的代码。开发人员站点以https模式显示页面,效果很好。没有重定向问题。此操作只应用了一个属性。请查看IIS日志以了解传入的请求。。。我很有可能它们都是HTTP,因为在服务器之前的某个地方。@learning…这里的大部分答案是-prod是负载平衡的。当您检查负载平衡器是否配置为执行SSL终止时,其余部分将被清除。改为阅读标题,你的生活会很好。OP已经得到重定向,它只是没有结束。。。因此,Web.Config更改的行为可能与此完全相同,但也有点简单。我在生产应用程序中使用此代码,当我们在本地工作时,我们只需将启用值设置为false,如上面的示例所示,当我们部署到生产服务器时,我们只需将值更改为true,然后部署。我们也在IE、Firefox、Chrome和最流行的移动浏览器上进行了测试,它对我们来说很有吸引力。这难道不会让所有页面都使用https吗?是的,但如果你有SSL证书,那么就没有理由使用非https。我们的要求就是这样,但是,如果您只希望保护特定页面,则可以编辑匹配url。我发现保护所有页面没有什么害处,客户喜欢在浏览器中看到安全图标:OP已经获得重定向,它只是没有结束。。。因此,Web.Config更改的行为可能与此完全相同,但也有点简单。我在生产应用程序中使用此代码,当我们在本地工作时,我们只需将启用值设置为false,如上面的示例所示,当我们部署到生产服务器时,我们只需将值更改为true,然后部署。我们也在IE、Firefox、Chrome和最流行的移动浏览器上进行了测试,它对我们来说很有吸引力。这难道不会让所有页面都使用https吗?是的,但如果你有SSL证书,那么就没有理由使用非https。我们的要求就是这样,但是,如果您只希望保护特定页面,则可以编辑匹配url。我发现保护所有页面没有什么害处,客户喜欢在浏览器中看到安全图标: