You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

IdentityServer4集成ADFS后如何实现外部提供商联动登出?

解决IdentityServer4触发ADFS 4.0同步登出的配置指南

首先,你的场景里ADFS已经支持OIDC的前端通道登出(暴露了end_session_endpointfrontchannel_logout_supported等属性),所以我们只需要正确配置IdentityServer4(IS4)和ADFS的OIDC客户端,就能实现同步登出。下面分步骤说明:

1. 先确认ADFS端的OIDC客户端配置

IS4作为ADFS的OIDC客户端,必须在ADFS里完成正确的登出配置:

  • 打开ADFS管理控制台,找到你为IS4注册的应用程序。
  • 进入属性 -> 高级,启用Front Channel Logout
  • 设置Front Channel Logout URI为IS4的OIDC登出回调地址,通常是https://你的IS4域名/signout-callback-oidc,这个地址必须在ADFS的信任列表里。

2. 配置IS4的外部OIDC提供商(ADFS)

在IS4的Startup.cs(或对应的配置类)中,配置ADFS作为外部OIDC提供商时,要确保以下关键项:

services.AddAuthentication()
    .AddOpenIdConnect("ADFS", "ADFS", options =>
    {
        options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
        options.SignOutScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
        options.Authority = "https://你的ADFS域名/adfs";
        options.ClientId = "你在ADFS里注册的IS4客户端ID";
        options.ResponseType = "code id_token";
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        // 确保IS4不依赖ADFS的令牌生命周期来管理会话
        options.UseTokenLifetime = false;
        // 自动保留idp claim,IS4需要这个来识别外部提供商
        options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce", "iat", "c_hash");
    });

这里的核心是:

  • 确保SignOutScheme指向外部Cookie方案,IS4会用这个来触发外部提供商的登出。
  • 保留idp claim(ADFS会返回这个claim,标识用户的身份提供商),IS4需要这个值来知道要触发哪个外部提供商的登出流程。

3. 调整IS4的登出流程代码

在IS4的AccountController(或自定义登出控制器)的Logout方法中,需要根据用户的idp claim来触发ADFS的登出:

public async Task<IActionResult> Logout(string logoutId)
{
    var vm = await BuildLogoutViewModelAsync(logoutId);
    if (vm.ShowLogoutPrompt == false)
    {
        // 先处理客户端和IS4自身的登出
        await HttpContext.SignOutAsync(IdentityServerConstants.DefaultCookieAuthenticationScheme);
        
        // 获取用户的idp claim,判断是否来自外部提供商ADFS
        var idpClaim = User.FindFirst(JwtClaimTypes.IdentityProvider);
        if (idpClaim != null && idpClaim.Value != IdentityServerConstants.LocalIdentityProvider)
        {
            var props = new AuthenticationProperties
            {
                RedirectUri = vm.PostLogoutRedirectUri // 登出ADFS后跳回的地址
            };
            // 触发ADFS的登出
            await HttpContext.SignOutAsync(idpClaim.Value, props);
        }

        return Redirect(vm.PostLogoutRedirectUri);
    }

    return View(vm);
}

这段代码的作用是:

  • 先清除IS4自身的会话Cookie。
  • 检查用户是否来自外部提供商(ADFS),如果是,调用SignOutAsync并传入ADFS的scheme(也就是idp claim的值),IS4会自动重定向到ADFS的end_session_endpoint,触发ADFS的登出。

4. 关于前端通道vs后端通道登出的选择

你的场景里,前端通道登出是正确的选择:

  • 前端通道登出是通过在页面中嵌入iframe,加载ADFS的登出端点,从而清除ADFS的会话Cookie,这也是ADFS 4.0支持的标准方式(你已经确认ADFS暴露了frontchannel_logout_supported属性)。
  • 后端通道登出是ADFS主动回调IS4的端点,用于用户在其他地方登出ADFS时通知IS4清除会话,并不适用于IS4触发ADFS登出的场景,所以不需要配置。

5. 验证配置是否生效

  • 访问ADFS的元数据地址(https://你的ADFS域名/adfs/.well-known/openid-configuration),确认end_session_endpoint存在,且frontchannel_logout_supportedtrue
  • 测试登出流程:登录客户端 -> 登出 -> 访问ADFS的身份验证页面(比如https://你的ADFS域名/adfs/ls/idpinitiatedsignon.aspx),如果需要重新输入用户名密码,说明ADFS的会话已经被清除,同步登出生效。

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

火山引擎 最新活动