仅在IdentityServer4中注销客户端

时间:2019-07-08 14:51:49

标签: identityserver4

是否有一种方法可以使用IdentityServer4仅对客户端执行一次登出?使用endsession端点为客户端和IdentityServer执行单点注销没有问题。但是,我想做的是提供一种方法,可以强制所有客户端在下一个请求时重新进行身份验证(以获取新的声明),而不是强制用户重新输入凭据。

该用例用于用户编辑存储在声明中的配置文件信息。例如,他们的名字。当用户对此信息提交更改时,需要使所有其他客户知道他们当前拥有的声明不再有效。可以通过将用户完全注销来实现,但是用户必须重新输入其ID和密码。

看一下流程,我想我想做的是直接执行内部EndSessionCallbackEndpoint,而不删除IdentityServer本身的身份验证cookie。

2 个答案:

答案 0 :(得分:1)

以下是一个可行的解决方案,但确实感觉就像我在滥用系统。如果有人可以通过“标准”方式提供期望的功能,请告诉我。

此解决方案将Logout方法更改为“嗅探”魔法PostLogoutRedirectUri,并跳过了删除本地身份验证cookie的操作。显然不是特别可伸缩或优雅。

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
    // build a model so the logged out page knows what to display
    var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);

    // Special post-logout URL that should only log out clients, but keep the local authentication cookie.
    bool clientsOnly = !string.IsNullOrEmpty(vm.PostLogoutRedirectUri) && vm.PostLogoutRedirectUri.StartsWith("https://example.com/EditProfile");

    if (User?.Identity.IsAuthenticated == true && !clientsOnly)
    {
        // delete local authentication cookie
        await _signInManager.SignOutAsync();

        // raise the logout event
        await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
    }

    // check if we need to trigger sign-out at an upstream identity provider
    if (vm.TriggerExternalSignout)
    {
        // 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.
        string url = Url.Action("Logout", new { logoutId = vm.LogoutId });

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

    return View("LoggedOut", vm);
}

答案 1 :(得分:0)

这非常简单,并通过IDS4中的公共API(IIdentityServerInteractionService)公开。这是步骤的真正简化示例。这涵盖了来自和从反向通道的退出,因为两者都由对SignOutIFrameUrl的请求触发。

首先,我们需要创建一个登出上下文并重定向到将执行登出的操作:

var signoutId = await _identityInteractionService.CreateLogoutContextAsync();
return RedirectToAction(nameof(ClientSignout), new { signoutId });

ClientSignout操作:

var context = await _identityInteractionService.GetLogoutContextAsync(signoutId);
ViewBag.SignOutIframeUrl = context.SignOutIFrameUrl;
return View();

ClientSignout.cshtml:

<iframe src="@ViewBag.SignOutIframeUrl" id="SignOutIframe" frameborder="0" scrolling="no" style="display:none" />
//TODO: Detect client-side once iframe has loaded and then maybe redirect somewhere else?

此处的代码完全不涉及当前的身份验证会话,但是另一种方法是强制刷新当前会话ID,从而在所有具有会话监视功能的客户端中触发刷新。

ETA:我考虑得更多,我认为客户端会话监视方法是正确的方法。客户可以控制接下来要做什么。另一个选择是客户端定期调用userinfo端点以使用提供的访问令牌获得更新的声明。实际上,我们全部使用了三种机制。