【发布时间】:2019-10-01 10:09:42
【问题描述】:
我在成功注销后无法正确返回客户端应用程序。首先,我想描述一下我的设置。
- IdentityServer4 作为 IDP
- 2x ASP.NET Core MVC 应用程序(从 IS4 角度看的客户端)。 MVC 应用程序使用两种身份验证方案(用于身份验证的“oidc”-cookie 方案和用于 rest api 调用的 JWT Bearer 令牌方案)
- 2x Angular 7 SPA(由上述 MVC 应用托管)
因为我的项目对安全性要求很高,所以我使用 混合流程 进行授权。 所以登录流程如下:
- 用户未通过身份验证并访问 SPA 应用程序,他点击了登录按钮
- Angular 应用程序重定向到 [Authorize] 属性下的 MVC 端点,这会启动 OIDC 质询。
- 用户被重定向(通过 OidcMiddleware)到 IS4,他可以在其中输入用户名和密码
- 正在将用户(成功登录后)重定向回 MVC 登录端点逻辑(在 pt.2 中调用),该逻辑负责将用户重定向回 Angular SPA。
- Angular 对 [Authorize] 下的 MVC 端点进行 http 调用,并负责将由 IS4 JWT 生成的令牌返回给客户端。
- 由于用户登录到 MVC 客户端(存在 cookie),MVC 后端从 cookie 中提取 JWT 令牌 (access_token) 并将其返回给客户端
- 此时登录流程已完成(REST API 的角度使用调用 JWT 令牌) - 因为我在后端使用了两种身份验证方案。
所以现在我在注销功能方面遇到了一些问题。首先要描述注销流程:
- 已登录的用户单击 Angular 应用程序中的注销按钮
-
Spa 应用程序清除本地存储条目(存储 JWT 令牌的位置)并将用户重定向到 MVC 应用程序上的注销操作。代码如下:
[允许匿名] 公共异步任务注销(字符串 returnUrl) { 等待 HttpContext.SignOutAsync("Cookies"); 等待 HttpContext.SignOutAsync("oidc"); }
“oidc”方案上的 SignoutAsync 触发 OIDC 注销流程(重定向到 IS4 注销端点)
-
IS4 注销端点正在加载注销上下文(代码来自 IS4 快速入门)
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Logout(LogoutDto dto) { // build a model so the logged out page knows what to display var vm = await BuildLoggedOutViewModelAsync(dto.LogoutId); if (User?.Identity.IsAuthenticated == true) { // delete local authentication cookie await HttpContext.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); } -
重要的是 BuildLoggedOutViewModelAsync 方法,它加载注销上下文:
私有异步任务 BuildLoggedOutViewModelAsync(string logoutId) { // 获取上下文信息(客户端名称、注销后重定向 URI 和联合注销的 iframe) var context = await _interaction.GetLogoutContextAsync(logoutId);
var vm = new LoggedOutViewModel { AutomaticRedirectAfterSignOut = AccountOptions.AutomaticRedirectAfterSignOut, PostLogoutRedirectUri = context?.PostLogoutRedirectUri, ClientName = string.IsNullOrEmpty(context?.ClientName) ? context?.ClientId : context?.ClientName, SignOutIframeUrl = context?.SignOutIFrameUrl, LogoutId = logoutId }; if (User?.Identity.IsAuthenticated == true) { var idp = User.FindFirst(JwtClaimTypes.IdentityProvider)?.Value; if (idp != null && idp != IdentityServerConstants.LocalIdentityProvider) { var providerSupportsSignout = await HttpContext.GetSchemeSupportsSignOutAsync(idp); if (providerSupportsSignout) { if (vm.LogoutId == null) { // if there's no current logout context, we need to create one // this captures necessary info from the current logged in user // before we signout and redirect away to the external IdP for signout vm.LogoutId = await _interaction.CreateLogoutContextAsync(); } vm.ExternalAuthenticationScheme = idp; } } } return vm; } 这就是问题所在。在这种情况下,我的 mvc cookie 已过期,上下文的大多数属性设置为 null,例如 PostLogoutRedirectUrl。因此,我无法在 IS4 LoggedOut.cshtml 视图上显示返回客户端链接。
在这种情况下,我的 mvc 客户端 cookie 没有过期(有效),一切正常。我有 PostLogoutRedirectUrl,它允许我从 IS4 返回到触发注销的客户端。
各位,你们有什么想法吗,我该如何解决这个问题?非常感谢您!
【问题讨论】:
-
但是IDS4 cookie应该和你的MVC cookie是分开的,怎么会过期呢?
-
你好。是的,你是对的 IS4 cookie 与 MVC cookie 是分开的。但默认情况下,MVC cookie 的有效期为 20 分钟。因此,如果用户处于非活动状态超过 20 分钟,这些 cookie 将过期。并且在注销期间,IS4 将没有关于客户端的信息。
-
这就是身份提供者 cookie 通常不会很快过期的原因。我认为您在错误的地方寻找问题。
-
嗯,老实说,我不知道。我正在玩 IS4 团队提供的快速入门示例,它们包含我描述的问题(MVC 客户端和 IS4 混合流)。因此,对于某些用户而言,这可能不是问题,但在我的情况下,我有要求,注销后我们应该重定向到客户端应用程序。
-
登录时有没有点击记住我?
标签: angular cookies identityserver4 logout asp.net-core-2.2