Request.Url.Scheme在负载平衡站点上给出http而不是https

lea*_*... 23 c# asp.net-mvc

我正在测试新的负载平衡暂存站点,并且https是在负载均衡器级别设置的,而不是在站点级别.此外,这个网站将始终是https所以我不需要远程需要https属性等.网址显示https但它在我的代码中不可用.由于这个原因,我有一些问题

Request.Url.Scheme总是http:

public static string GetProtocol()
        {
            var protocol = "http";
            if (HttpContext.Current != null && HttpContext.Current.Request != null)
            {
                protocol = HttpContext.Current.Request.Url.Scheme;
            }
            return protocol;
        }
Run Code Online (Sandbox Code Playgroud)

与此基本URL相同,协议是http

public static string GetBaseUrl()
        {
            var baseUrl = String.Empty;

            if (HttpContext.Current == null || HttpContext.Current.Request == null || String.IsNullOrWhiteSpace(HttpRuntime.AppDomainAppPath)) return baseUrl;

            var request = HttpContext.Current.Request;
            var appUrl = HttpRuntime.AppDomainAppVirtualPath;

            baseUrl = string.Format("{0}://{1}{2}", request.Url.Scheme, request.Url.Authority, appUrl);

            if (!string.IsNullOrWhiteSpace(baseUrl) && !baseUrl.EndsWith("/"))
                baseUrl = String.Format("{0}/", baseUrl);

            return baseUrl;
        }
Run Code Online (Sandbox Code Playgroud)

现在最大的问题是引用样式表中引用的js文件和谷歌字体.我在这里使用//没有http或https,但这些被视为http,我在FireBug中看到混合内容被阻止的消息.

我怎样才能克服这个问题?

Ale*_*kov 16

正如您所说,HTTPS终止是在负载均衡器级别完成的("https是在负载均衡器级别设置的"),这意味着原始方案可能不会到达站点,具体取决于负载均衡器配置.

看起来在您的情况下,LB配置为始终通过HTTP与站点通信.因此,您的网站永远不会看到原始方案HttpContext.Request.RawUrl(或类似的属性).

修复:通常当LB,代理或CDN以这种方式配置时,会有额外的标头指定原始方案以及可能的其他传入请求参数,例如完整URL,客户端的IP,这些代理设备后面的站点将不会直接看到.


Bou*_*uke 8

我覆盖ServerVariables以说服 MVC 它确实是通过 HTTPS 进行通信并公开用户的 IP 地址。这是使用负载均衡器设置的X-Forwarded-ForX-Forwarded-ProtoHTTP 标头。

请注意,如果您真的确定这些标头在您的控制之下,您应该只使用它,否则客户端可能会注入他们喜欢的值。

public sealed class HttpOverrides : IHttpModule
{
    void IHttpModule.Init(HttpApplication app)
    {
        app.BeginRequest += OnBeginRequest;
    }

    private void OnBeginRequest(object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;

        string forwardedFor = app.Context.Request.Headers["X-Forwarded-For"]?.Split(new char[] { ',' }).FirstOrDefault();
        if (forwardedFor != null)
        {
            app.Context.Request.ServerVariables["REMOTE_ADDR"] = forwardedFor;
            app.Context.Request.ServerVariables["REMOTE_HOST"] = forwardedFor;
        }

        string forwardedProto = app.Context.Request.Headers["X-Forwarded-Proto"];
        if (forwardedProto == "https")
        {
            app.Context.Request.ServerVariables["HTTPS"] = "on";
            app.Context.Request.ServerVariables["SERVER_PORT"] = "443";
            app.Context.Request.ServerVariables["SERVER_PORT_SECURE"] = "1";
        }
    }

    void IHttpModule.Dispose()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

并在Web.config

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
        <add name="HttpOverrides" type="Namespace.HttpOverrides" preCondition="integratedMode" />
    </modules>
</system.webServer>
Run Code Online (Sandbox Code Playgroud)