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

  1. 结果302.请求https://localhost:5999/Account/ExternalLoginCallback?state=xxx&code=xxx&session_state=xxx
  2. 然后请求到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}";
                }

现在它按预期工作了