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

Duende IdentityServer:RP登出跳转后无认证用户,联邦登出失效

问题:Duende IdentityServer联邦登出时无已认证用户导致外部登出失效

我正在遵循Duende IdentityServer的第2个快速入门教程,已完成IdentityServer和依赖方(RP)Web应用的创建,登录、登出功能正常。添加外部登录提供商后登录正常,但想要实现联邦登出(从RP登出时同时退出IdentityServer和外部提供商)时遇到问题:

当从RP登出并跳转到IdentityServer的Logout/Index.cshtml.cs的OnGet方法时,始终不存在已认证用户,导致showLogoutPrompt一直为false,直接调用OnPost(),而处理联邦登出的代码因为没有已认证用户永远不会执行。


RP的SignOut.cshtml.cs代码

public class SignOutModel : PageModel
{
    public IActionResult OnGet()
    {
        return SignOut("Cookies", "oidc");
    }
}

IdentityServer的Logout/Index.cshtml.cs OnGet方法

public async Task<IActionResult> OnGet(string? logoutId)
{
    LogoutId = logoutId;

    var showLogoutPrompt = LogoutOptions.ShowLogoutPrompt;

    if (User.Identity?.IsAuthenticated != true) // 此处始终为false
    {
        // if the user is not authenticated, then just show logged out page
        showLogoutPrompt = false;
    }
    else
    {
        var context = await _interaction.GetLogoutContextAsync(LogoutId);
        if (context?.ShowSignoutPrompt == false)
        {
            // it's safe to automatically sign-out
            showLogoutPrompt = false;
        }
    }

    if (showLogoutPrompt == false)
    {
        // if the request for logout was properly authenticated from IdentityServer, then
        // we don't need to show the prompt and can just log the user out directly.
        return await OnPost();
    }

    return Page();
}

IdentityServer的Logout/Index.cshtml.cs OnPost方法

public async Task<IActionResult> OnPost()
{
    if (User.Identity?.IsAuthenticated == true) // 此处始终为false
    {
        // if there's no current logout context, we need to create one
        // this captures necessary info from the current logged in user
        // this can still return null if there is no context needed
        LogoutId ??= await _interaction.CreateLogoutContextAsync();

        // delete local authentication cookie
        await HttpContext.SignOutAsync();

        // see if we need to trigger federated logout
        var idp = User.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;

        // raise the logout event
        await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
        Telemetry.Metrics.UserLogout(idp);

        // if it's a local login we can ignore this workflow
        if (idp != null && idp != Duende.IdentityServer.IdentityServerConstants.LocalIdentityProvider)
        {
            // we need to see if the provider supports external logout
            if (await HttpContext.GetSchemeSupportsSignOutAsync(idp))
            {
                // build a return URL so the upstream provider will redirect back
                // to us after the user has logged out. this allows us to then
                // complete our single sign-out processing.
                var url = Url.Page("/Account/Logout/Loggedout", new { logoutId = LogoutId });

                // this triggers a redirect to the external provider for sign-out
                return SignOut(new AuthenticationProperties { RedirectUri = url }, idp);
            }
        }
    }

    return RedirectToPage("/Account/Logout/LoggedOut", new { logoutId = LogoutId });
}

我想知道为什么始终没有已认证用户?是不是RP调用SignOut("Cookies","oidc")时,在跳转到IdentityServer之前就移除了会话Cookie?我认为RP无法删除IdP的会话Cookie(因为属于不同域),但可能我错了。另外,请求/connect/endsession中并不包含该Cookie。

我严格遵循了快速入门教程,这种行为是有意设计的吗?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 23:44:50