是否有一种方法可以使用IdentityServer4仅对客户端执行一次登出?使用endsession
端点为客户端和IdentityServer执行单点注销没有问题。但是,我想做的是提供一种方法,可以强制所有客户端在下一个请求时重新进行身份验证(以获取新的声明),而不是强制用户重新输入凭据。
该用例用于用户编辑存储在声明中的配置文件信息。例如,他们的名字。当用户对此信息提交更改时,需要使所有其他客户知道他们当前拥有的声明不再有效。可以通过将用户完全注销来实现,但是用户必须重新输入其ID和密码。
看一下流程,我想我想做的是直接执行内部EndSessionCallbackEndpoint
,而不删除IdentityServer本身的身份验证cookie。
答案 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端点以使用提供的访问令牌获得更新的声明。实际上,我们全部使用了三种机制。