【问题标题】:Sign-out IdentityServer4 + ASP.NET Core MVC + Angular application注销 IdentityServer4 + ASP.NET Core MVC + Angular 应用程序
【发布时间】: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 应用托管)

因为我的项目对安全性要求很高,所以我使用 混合流程 进行授权。 所以登录流程如下:

  1. 用户未通过身份验证并访问 SPA 应用程序,他点击了登录按钮
  2. Angular 应用程序重定向到 [Authorize] 属性下的 MVC 端点,这会启动 OIDC 质询。
  3. 用户被重定向(通过 OidcMiddleware)到 IS4,他可以在其中输入用户名和密码
  4. 正在将用户(成功登录后)重定向回 MVC 登录端点逻辑(在 pt.2 中调用),该逻辑负责将用户重定向回 Angular SPA。
  5. Angular 对 [Authorize] 下的 MVC 端点进行 http 调用,并负责将由 IS4 JWT 生成的令牌返回给客户端。
  6. 由于用户登录到 MVC 客户端(存在 cookie),MVC 后端从 cookie 中提取 JWT 令牌 (access_token) 并将其返回给客户端
  7. 此时登录流程已完成(REST API 的角度使用调用 JWT 令牌) - 因为我在后端使用了两种身份验证方案。

所以现在我在注销功能方面遇到了一些问题。首先要描述注销流程:

  1. 已登录的用户单击 Angular 应用程序中的注销按钮
  2. Spa 应用程序清除本地存储条目(存储 JWT 令牌的位置)并将用户重定向到 MVC 应用程序上的注销操作。代码如下:

    [允许匿名] 公共异步任务注销(字符串 returnUrl) { 等待 HttpContext.SignOutAsync("Cookies"); 等待 HttpContext.SignOutAsync("oidc"); }

  3. “oidc”方案上的 SignoutAsync 触发 OIDC 注销流程(重定向到 IS4 注销端点)

  4. 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);
    }
    
  5. 重要的是 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;
    }
    
  6. 这就是问题所在。在这种情况下,我的 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


【解决方案1】:
  1. “Spa 应用程序清除本地存储条目(存储 JWT 令牌的位置)并将用户重定向到 MVC 应用程序上的注销操作。”

^^我不认为你应该做上述步骤。 IDS 会处理它。

【讨论】:

  • 不,不会。 IDS 对 Spa 应用程序一无所知。从 IDS 的角度来看,MVC 应用程序是“客户端”。
猜你喜欢
  • 2013-08-19
  • 2023-04-03
  • 2018-05-09
  • 1970-01-01
  • 2017-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-26
相关资源
最近更新 更多