IdentityServer4 和外部 oauth 提供者:oauth 状态丢失或无效
IdentityServer4 and external oauth privider: The oauth state was missing or invalid
我正在尝试在 IdentityServer4 中实施外部 oauth 身份验证。
所有身份验证请求都成功进行。我有一条消息 AuthenticationScheme: Identity.External signed in. 在应用程序日志中。
但是,当身份验证过程尝试返回到 ExternalLoginCallback 操作时,它会在 HTTP 302 之后出现错误 500(oauth 状态丢失或无效)。
Screenshot is here
- 结果302.请求https://localhost:5999/Account/ExternalLoginCallback?state=xxx&code=xxx&session_state=xxx
- 然后请求到https://localhost:5999/Account/ExternalLoginCallback(没有任何参数)
我的 IS4 启动
IdentityServerConfiguration.AddIdentityServer(services, _configuration);
services
.AddAuthentication()
.AddTinkoff(_configuration)
.AddSber(_configuration)
.AddEsia(_configuration);
AddTinkoff扩展方法:
public static AuthenticationBuilder AddTinkoff(this AuthenticationBuilder builder, IConfiguration config)
{
return builder.AddOAuth("TinkoffId", "Tinkoff ID", options =>
{
options.AuthorizationEndpoint = "https://id.tinkoff.ru/auth/authorize?response_type=code";
options.TokenEndpoint = "https://id.tinkoff.ru/auth/token?grant_type=authorization_code";
options.UserInformationEndpoint = "https://id.tinkoff.ru/userinfo/userinfo";
options.CallbackPath = "/Account/ExternalLoginCallback";
options.ClientId = "xxx";
options.ClientSecret = "xxxx";
options.SaveTokens = true;
options.SignInScheme = IdentityConstants.ExternalScheme;
options.BackchannelHttpHandler = new TinkoffAuthorizingHandler(new HttpClientHandler(), options);
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "name");
options.ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email);
options.ClaimActions.MapAll();
options.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
var request = new HttpRequestMessage(HttpMethod.Post, context.Options.UserInformationEndpoint);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
request.Headers.Add(
HttpRequestHeader.ContentType.ToString(),
"application/x-www-form-urlencoded"
);
request.Content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>() {
new KeyValuePair<string, string>("client_id",options.ClientId),
new KeyValuePair<string, string>("client_secret",options.ClientSecret)
});
var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
var user = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
context.RunClaimActions(user.RootElement);
},
//OnTicketReceived = async context =>
//{
// context.HttpContext.User = context.Principal;
// //context.SkipHandler();
//}
};
//options.Scope.Add("profile");
//options.Scope.Add("email");
//options.Scope.Add("phone");
});
}
我的 ExternalLogin 操作:
[HttpPost]
[HttpGet]
[AllowAnonymous]
public IActionResult ExternalLogin(string provider, string returnUrl = null)
{
_logger.LogInformation($"External login fired. ReturnUrl='{returnUrl}'. Provider='{provider}'");
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
调试时未触发 ExternalLoginCallback 操作。
我做错了什么。为什么请求在没有参数的情况下重定向到自身?
谢谢。
帮我解决了一个问题。
我加了
OnTicketReceived = async context =>
{
context.HttpContext.User = context.Principal;
//context.SkipHandler();
context.ReturnUri += $"/{context.Request.QueryString}";
}
现在它按预期工作了
我正在尝试在 IdentityServer4 中实施外部 oauth 身份验证。 所有身份验证请求都成功进行。我有一条消息 AuthenticationScheme: Identity.External signed in. 在应用程序日志中。 但是,当身份验证过程尝试返回到 ExternalLoginCallback 操作时,它会在 HTTP 302 之后出现错误 500(oauth 状态丢失或无效)。 Screenshot is here
- 结果302.请求https://localhost:5999/Account/ExternalLoginCallback?state=xxx&code=xxx&session_state=xxx
- 然后请求到https://localhost:5999/Account/ExternalLoginCallback(没有任何参数)
我的 IS4 启动
IdentityServerConfiguration.AddIdentityServer(services, _configuration);
services
.AddAuthentication()
.AddTinkoff(_configuration)
.AddSber(_configuration)
.AddEsia(_configuration);
AddTinkoff扩展方法:
public static AuthenticationBuilder AddTinkoff(this AuthenticationBuilder builder, IConfiguration config)
{
return builder.AddOAuth("TinkoffId", "Tinkoff ID", options =>
{
options.AuthorizationEndpoint = "https://id.tinkoff.ru/auth/authorize?response_type=code";
options.TokenEndpoint = "https://id.tinkoff.ru/auth/token?grant_type=authorization_code";
options.UserInformationEndpoint = "https://id.tinkoff.ru/userinfo/userinfo";
options.CallbackPath = "/Account/ExternalLoginCallback";
options.ClientId = "xxx";
options.ClientSecret = "xxxx";
options.SaveTokens = true;
options.SignInScheme = IdentityConstants.ExternalScheme;
options.BackchannelHttpHandler = new TinkoffAuthorizingHandler(new HttpClientHandler(), options);
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "name");
options.ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email);
options.ClaimActions.MapAll();
options.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
var request = new HttpRequestMessage(HttpMethod.Post, context.Options.UserInformationEndpoint);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
request.Headers.Add(
HttpRequestHeader.ContentType.ToString(),
"application/x-www-form-urlencoded"
);
request.Content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>() {
new KeyValuePair<string, string>("client_id",options.ClientId),
new KeyValuePair<string, string>("client_secret",options.ClientSecret)
});
var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
var user = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
context.RunClaimActions(user.RootElement);
},
//OnTicketReceived = async context =>
//{
// context.HttpContext.User = context.Principal;
// //context.SkipHandler();
//}
};
//options.Scope.Add("profile");
//options.Scope.Add("email");
//options.Scope.Add("phone");
});
}
我的 ExternalLogin 操作:
[HttpPost]
[HttpGet]
[AllowAnonymous]
public IActionResult ExternalLogin(string provider, string returnUrl = null)
{
_logger.LogInformation($"External login fired. ReturnUrl='{returnUrl}'. Provider='{provider}'");
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
调试时未触发 ExternalLoginCallback 操作。
我做错了什么。为什么请求在没有参数的情况下重定向到自身?
谢谢。
帮我解决了一个问题。 我加了
OnTicketReceived = async context =>
{
context.HttpContext.User = context.Principal;
//context.SkipHandler();
context.ReturnUri += $"/{context.Request.QueryString}";
}
现在它按预期工作了