负载均衡器中断外部登录,因为重定向 uri 是 http(不是 https)

Load Balancer breaks external login, because redirect uri is http (not https)

我正在使用 ASP.NET MVC,我正在使用 MS 内置模板以允许用户使用 Facebook 和 Google、外部 ID 登录。外部 ID 在我的生产环境中不起作用(在测试中起作用),我相信这是因为负载平衡器...(我在负载平衡器上卸载 SSL,后端服务器使用 HTTP)。

我已经看到 并且我 认为 这是我的问题:登录请求包含 returnurl 并且因为后端服务器正在使用 http, return url 也是 http(不是 https)。这就是我在 AccountController:

中所说的方法
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
    // Request a redirect to the external login provider
    return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}

当用户尝试登录时,我可以看到 redirect_uri 是 http(不是 https):

我已经检查了上面提到的问题,也。他们都建议我应该在 Startup.Auth 中使用相对路径进行重定向 url,所以这就是我添加到代码中的内容(ConfigureAuth 方法):

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    {
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, long>(
            validateInterval: TimeSpan.FromMinutes(30),
            regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
            getUserIdCallback: id => id.GetUserId<long>()),

        /* THIS IS THE CHANGE THAT I HAVE ADDED */
        OnApplyRedirect = context =>
        {
            /* I have tried adding a breakpoint here, but it is never hit */
            var redirectUri = new Uri(context.RedirectUri, UriKind.Absolute);

            if (redirectUri.Scheme == "http" && redirectUri.Host == context.Request.Uri.Host)
            {
                context.RedirectUri = redirectUri.PathAndQuery;
            }

            context.Response.Redirect(context.RedirectUri);
        }
    }
});

但此更改没有效果,redirect_url 仍然是 http。如果我在上面添加的更改上放置一个断点,断点永远不会命中...不确定哪里出了问题?

我找到了使用 & this github issue 的解决方案:

负载均衡器将终止 SSL 并使用 http 与后端服务器通信,但它会将原始协议(在本例中为 https)转发到后端服务器。所以我们可以使用 x-forwarded-proto 来检测后端服务器中的原始协议:

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and signin manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

        /* I HAVE ADDED THIS CODE */
        app.Use((context, next) =>
        {
            if (context.Request.Headers["x-forwarded-proto"] == "https")
            {
                context.Request.Scheme = "https";
            }
            return next();
        });

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, long>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
                    getUserIdCallback: id => id.GetUserId<long>())
            }
        });

        // more code...
}