注销外部身份提供商

当用户从 IdentityServer 注销 时,如果他们使用了 外部身份提供商 登录,则很可能还应该将他们重定向到注销外部提供商。 并非所有外部提供商都支持注销,因为这取决于他们支持的协议和功能。

检测用户是否必须重定向到外部身份提供商以进行注销,通常是通过使用在 IdentityServer 的 cookie 中发出的 idp 声明来完成的。 设置到此声明中的值是相应身份验证中间件的 AuthenticationScheme。 在注销时,将咨询此声明以了解是否需要外部注销。

由于正常注销工作流已经需要清理和状态管理,因此将用户重定向到外部身份提供者是有问题的。 完成 IdentityServer 的正常注销和清理过程的唯一方法是,从外部身份提供商请求在其注销后,将用户重定向回 IdentityServer。 并非所有外部提供商都支持注销后重定向,因为这取决于它们支持的协议和功能。

注销时的工作流程是撤销 IdentityServer 的身份验证 cookie,然后重定向到请求注销后重定向的外部提供商。 注销后重定向应保持 此处 描述的必要注销状态(即 logoutId 参数值)。 要在外部提供商注销后重定向回 IdentityServer,例如,当使用 ASP.NET Core 的 SignOutAsync API 时,应在 AuthenticationProperties 上使用 RedirectUri:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
    // 建立一个模型,以便注销页面知道要显示什么
    var vm = await _account.BuildLoggedOutViewModelAsync(model.LogoutId);

    var user = HttpContext.User;
    if (user?.Identity.IsAuthenticated == true)
    {
        // 删除本地认证cookie
        await HttpContext.SignOutAsync();

        // 引发注销事件
        await _events.RaiseAsync(new UserLogoutSuccessEvent(user.GetSubjectId(), user.GetName()));
    }

    // 检查我们是否需要在上游身份提供商处触发注销
    if (vm.TriggerExternalSignout)
    {
        // 构建一个返回 URL,以便上游提供商在用户注销后重定向回我们。
        // 这样我们就可以完成单点注销处理。
        string url = Url.Action("Logout", new { logoutId = vm.LogoutId });

        // 这将触发重定向到外部提供商以进行注销
        return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
    }

    return View("LoggedOut", vm);
}

一旦用户从外部提供商注销,然后重定向回来,IdentityServer 上的正常注销处理就应该执行,这包括处理 logoutId 并进行所有必要的清理。