IdentityServer4 重定向到注销页面而不是 PostLogoutRedirectUri

Posted

技术标签:

【中文标题】IdentityServer4 重定向到注销页面而不是 PostLogoutRedirectUri【英文标题】:IdentityServer4 redirects to Logout page instead of PostLogoutRedirectUri 【发布时间】:2021-06-15 23:22:15 【问题描述】:

我创建了 AspNetCore 3.1 项目并为 SSO 添加了 IdentityServer4(添加了“Microsoft.AspNetCore.ApiAuthorization.IdentityServer”包)。登录可以正常工作,但注销不行。

在 Startup.cs 中,我对 IdentityServer 进行了以下配置:

public void ConfigureServices(IServiceCollection services)

    ...
    services.AddIdentityServer()
          .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
                 ...
                    var client = new Client
                    
                        ClientName = "ssotestclient",
                        ClientId = "ssotestclient",
                        ClientSecrets =  new Secret("somesecret".Sha256()) ,
                        AllowedGrantTypes = GrantTypes.Code.Union(GrantTypes.ResourceOwnerPasswordAndClientCredentials).ToArray(),
                        RequirePkce = false,
                        RequireClientSecret = false,
                        AllowOfflineAccess = false,
                        AlwaysSendClientClaims = true,
                        UpdateAccessTokenClaimsOnRefresh = true,
                        AlwaysIncludeUserClaimsInIdToken = true,
                        AllowedScopes = new List<string>
                        
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Email,
                            IdentityServerConstants.StandardScopes.Profile,
                            IdentityServerConstants.StandardScopes.OfflineAccess
                        ,
                        RequireConsent = false,
                        RedirectUris = "https://mytestsite.local/signin-oidc" ,
                        PostLogoutRedirectUris = "https://mytestsite.local/signout-callback-oidc"
                    
                    options.Clients.Add(client);
                 );

客户端网站是一个带有“Microsoft.AspNetCore.Authentication.OpenIdConnect”包的 AspNetCore MVC 项目。 Startup.cs 中的客户端初始化

        public void ConfigureServices(IServiceCollection services)
        
            services.AddAuthentication(options =>
                
                    options.DefaultScheme = "Cookies";
                    options.DefaultChallengeScheme = "oidc";
                )
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            
                options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.Authority = "https://myssoserver.local";
                options.RequireHttpsMetadata = false;
                HttpClientHandler handler = new HttpClientHandler();
                handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
                options.BackchannelHttpHandler = handler;
                options.ClientId = "ssotestclient";
                options.ClientSecret = "secret";
                options.ResponseType = "code";
                options.UsePkce = true;
                options.Scope.Add("email");
                options.Scope.Add("profile");
                options.SaveTokens = true;
            );
            services.AddAuthorization();
            services.AddRazorPages();
            services.AddControllers();
        

客户端网站上的注销按钮有以下代码:

        public async Task OnPostAsync(string returnUrl = null)
        
            await HttpContext.SignOutAsync("Cookies");
            await HttpContext.SignOutAsync("oidc");
        

在此之后,浏览器被重定向到具有以下位置的 SSO 服务器:

https://myssoserver.local/connect/endsession?post_logout_redirect_uri=https%3A%2F%2Fmytestsite.local%2Fsignout-callback-oidc&id_token_hint=<token>&state=<state>&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=5.5.0.0

tokenstate 的实际值从这篇文章中被删减,因为它们太长了。

如您所见,post_logout_redirect_uriid_token_hintstate 参数被传递到服务器 endsession 端点。 在 SSO 服务器端,我看到它已通过验证的消息:

info: IdentityServer4.Validation.EndSessionRequestValidator[0]
      End session request validation success
      
        "ClientId": "sso_test_client",
        "ClientName": "sso_test_client",
        "SubjectId": "f3693d8c-6095-4f1a-9f8f-bdc7440e9395",
        "PostLogOutUri": "https://mytestsite.local/signout-callback-oidc",
        "State": "<state>",
        "Raw": 
          "post_logout_redirect_uri": "https://mytestsite.local/signout-callback-oidc",
          "id_token_hint": "***REDACTED***",
          "state": "<state>",
          "x-client-SKU": "ID_NETSTANDARD2_0",
          "x-client-ver": "5.5.0.0"
        
      

然而,在此请求之后,浏览器会收到 302 重定向到 https://myssoserver.local/Identity/Account/Logout 页面,而不是提供的 post_logout_redirect_uri。 并且不会发生实际的注销,因为只调用了 OnGet() 处理程序,它什么都不做

在网上找不到类似的问题。

可能出了什么问题?为什么我会被重定向到注销页面而不是回调 uri?我搜索了项目代码,除了注销页面本身之外,找不到任何与“注销”字样的引用

【问题讨论】:

【参考方案1】:

一种想法是您需要设置 LogoutPath。

.AddCookie(选项 => options.LogoutPath = "/用户/注销"; )

LogoutPath 是一项安全功能,正如我的一个培训课程中的这张图片所示:

【讨论】:

问题是浏览器在 SSO 服务器的注销页面上没有调用 POST。它使用 GET 重定向 您可以忽略我图片中的 HttpPost 属性,但是,让注销按钮发布而不是 GET 是最佳做法。见security.stackexchange.com/questions/62769/… 我不想让用户单击应用程序服务器上的注销按钮,然后单击 SSO 服务器上的注销按钮。我想要应用程序服务器上的注销按钮,该按钮也会从 SSO 中注销用户。 这里不调用两者 await HttpContext.SignOutAsync("Cookies");等待 HttpContext.SignOutAsync("oidc");让你从两者中退出?一般来说应该。 应该,但没有。仅从客户端服务器注销,而不是从 SSO 服务器注销。所以下次我刷新客户端服务器页面时,我会自动从 SSO 获取一个新令牌,因为我仍然处于登录状态。

以上是关于IdentityServer4 重定向到注销页面而不是 PostLogoutRedirectUri的主要内容,如果未能解决你的问题,请参考以下文章

是否可以将 IdentityServer4 中的用户注销为其他用户?

mobilefirst注销重定向到新页面

在颤动中按下注销按钮后如何重定向到登录页面

登录到网站后,它会根据检查“网络”重定向到正确的页面,但是会注销并重新加载登录页面

带有 docker-compose 的 Identity Server 4 在 /connect/authorize/callback 之后重定向到登录页面

如何使用 Laravel 5.3 注销并重定向到登录页面?