我正在使用ASP.NET MVC,并且正在使用MS内置模板,以允许用户使用外部ID登录到Facebook和Google。外部ID在我的生产环境(在测试中可以工作)上不起作用,并且我相信这是由于负载均衡器...(我正在负载均衡器上卸载SSL,后端服务器使用HTTP)。
我见过This Question,并且我认为,这是我的问题:登录请求包含一个returnurl
,并且由于后端服务器使用的是http,因此返回网址也是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):
我已经检查了上述问题,也检查了this one。他们俩都建议我在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。如果我在上面添加的更改上设置了断点,则断点永远不会命中...不确定哪里出了问题?
答案 0 :(得分:1)
我找到了使用this question和this github issue的解决方案:
Load Balancer将终止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...
}