You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IdentityServer4集成Google外部登录后无法重定向至React客户端

问题:IdentityServer外部Google登录后无法从React客户端重定向到首页

我在应用中使用Google作为外部登录提供商,IdentityServer的基础地址为https://localhost:5001。直接在IdentityServer中登录时一切正常,但通过React客户端登录时,完全无法重定向至首页。我调试了外部控制器,发现传入Redirect方法的returnUrl是有效的。而不使用外部提供商,直接通过IdentityServer原生登录React客户端时,重定向到首页毫无问题,一切运行良好。

外部登录控制器代码

[SecurityHeaders]
[AllowAnonymous]
public class ExternalController : Controller
{
    private readonly IIdentityServerInteractionService _interaction;
    private readonly IClientStore _clientStore;
    private readonly ILogger<ExternalController> _logger;
    private readonly IEventService _events;
    public ExternalController(
        IIdentityServerInteractionService interaction,
        IClientStore clientStore,
        IEventService events,
        ILogger<ExternalController> logger)
    {
        _interaction = interaction;
        _clientStore = clientStore;
        _logger = logger;
        _events = events;
    }

    [HttpGet]
    public IActionResult Challenge(string scheme, string returnUrl)
    {
        if (string.IsNullOrEmpty(returnUrl)) returnUrl = "~/";

        if (Url.IsLocalUrl(returnUrl) == false && _interaction.IsValidReturnUrl(returnUrl) == false)
        {
            throw new Exception("invalid return URL");
        }

        var props = new AuthenticationProperties
        {
            RedirectUri = Url.Action(nameof(Callback)),
            Items =
            {
                { "returnUrl", returnUrl },
                { "scheme", scheme },
            }
        };

        return Challenge(props, scheme);

    }

    [HttpGet]
    public async Task<IActionResult> Callback()
    {
        var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

        if (result?.Succeeded != true)
        {
            throw new Exception("External authentication error");
        }

        var externalUser = result.Principal;

        if (externalUser == null)
        {
            throw new Exception("External authentication error");
        }

        var claims = externalUser.Claims.ToList();

        var userIdClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);

        if (userIdClaim == null)
        {
            throw new Exception("Unknown userid");
        }

        var email = claims.FirstOrDefault(c => c.Type == ClaimsTypes.Email).Value;
        var username = claims.FirstOrDefault(c => c.Type == ClaimsTypes.Name).Value;
        var externalProvider = userIdClaim.Issuer;

        await HttpContext.SignInAsync(new IdentityServerUser(userIdClaim.Value)
        {
            DisplayName = username,
            IdentityProvider = externalProvider,
            AdditionalClaims = new List<Claim>()
            {
                new Claim(ClaimTypes.Email, email),
            },
            AuthenticationTime = DateTime.UtcNow
        });

        await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);


        var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

        return Redirect(returnUrl);
    }
}

客户端配置(React应用基础地址为http://localhost:3000)

new Client()
{
    ClientId = "react-client-id",
    RequireClientSecret = false,
    RequireConsent = false,
    RequirePkce = true,
    ClientName = "React Client",
    AllowedCorsOrigins = {"http://localhost:3000"},
    RedirectUris = { "http://localhost:3000/callback", "http://localhost:3000/refresh" },
    PostLogoutRedirectUris = { "http://localhost:3000/logout" },
    AllowedGrantTypes =  GrantTypes.Code,
    AllowedScopes = {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Email,
        IdentityServerConstants.StandardScopes.Profile,
        "PetAPI",
        "ScheduleAPI"
    }
}

OAuth配置

builder.Services.AddAuthentication()
    .AddCookie()
    .AddGoogle("Google", options =>
    {
        options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

        options.ClientId = builder.Configuration["Authentication:Google:ClientId"];
        options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
    });

内容的提问来源于stack exchange,提问作者moltenessence

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 07:05:19