C# 从未使用IdentityServer 4的OIDC客户端注销

C# 从未使用IdentityServer 4的OIDC客户端注销,c#,identityserver4,openid-connect,.net-5,pkce,C#,Identityserver4,Openid Connect,.net 5,Pkce,我目前正在使用IdentityServer4开发一个.NET5应用程序 我使用授权码+PKCE流登录-不幸的是,在本地主机上注销似乎无法正常工作 我的应用程序环境如下所示: // Authorization Code + PKCE Flow new Client { ClientId = "oidcClient", ClientName = "Example App", ClientSecrets = { new Secret(&q

我目前正在使用IdentityServer4开发一个.NET5应用程序

我使用授权码+PKCE流登录-不幸的是,在本地主机上注销似乎无法正常工作

我的应用程序环境如下所示:

// Authorization Code + PKCE Flow
new Client
{
    ClientId = "oidcClient",
    ClientName = "Example App",
    ClientSecrets = { new Secret("secret".Sha256()) },

    RedirectUris = { "https://localhost:44301/signin-oidc" },
    PostLogoutRedirectUris = { "https://localhost:44301/signout-callback-oidc" },

    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = true,
    RequireClientSecret = true,
    
    AllowedScopes = 
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email,
        IdentityServerConstants.StandardScopes.OfflineAccess,
        "roles",
    },

    AllowPlainTextPkce = false,
},

services.AddAuthentication(options => 
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => 
{
    options.Authority = "https://localhost:5001";
    options.RequireHttpsMetadata = true;
    options.ClientId = "oidcClient";
    options.ClientSecret = "secret";

    options.ResponseType = "code";
    options.UsePkce = true;
    options.ResponseMode = "query";

    options.Scope.Add("offline_access");
    options.Scope.Add("roles");
    
    options.SaveTokens = true;
});

public async Task<IActionResult> Logout()
{
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);

    return new SignOutResult(new[] { OpenIdConnectDefaults.AuthenticationScheme, CookieAuthenticationDefaults.AuthenticationScheme });
}
  • 应用程序(网络应用程序)
  • 标识服务器4
IdentityServer4中的客户端定义如下所示:

// Authorization Code + PKCE Flow
new Client
{
    ClientId = "oidcClient",
    ClientName = "Example App",
    ClientSecrets = { new Secret("secret".Sha256()) },

    RedirectUris = { "https://localhost:44301/signin-oidc" },
    PostLogoutRedirectUris = { "https://localhost:44301/signout-callback-oidc" },

    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = true,
    RequireClientSecret = true,
    
    AllowedScopes = 
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email,
        IdentityServerConstants.StandardScopes.OfflineAccess,
        "roles",
    },

    AllowPlainTextPkce = false,
},

services.AddAuthentication(options => 
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => 
{
    options.Authority = "https://localhost:5001";
    options.RequireHttpsMetadata = true;
    options.ClientId = "oidcClient";
    options.ClientSecret = "secret";

    options.ResponseType = "code";
    options.UsePkce = true;
    options.ResponseMode = "query";

    options.Scope.Add("offline_access");
    options.Scope.Add("roles");
    
    options.SaveTokens = true;
});

public async Task<IActionResult> Logout()
{
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);

    return new SignOutResult(new[] { OpenIdConnectDefaults.AuthenticationScheme, CookieAuthenticationDefaults.AuthenticationScheme });
}
客户端应用程序上的我的OIDC connect如下所示:

// Authorization Code + PKCE Flow
new Client
{
    ClientId = "oidcClient",
    ClientName = "Example App",
    ClientSecrets = { new Secret("secret".Sha256()) },

    RedirectUris = { "https://localhost:44301/signin-oidc" },
    PostLogoutRedirectUris = { "https://localhost:44301/signout-callback-oidc" },

    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = true,
    RequireClientSecret = true,
    
    AllowedScopes = 
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email,
        IdentityServerConstants.StandardScopes.OfflineAccess,
        "roles",
    },

    AllowPlainTextPkce = false,
},

services.AddAuthentication(options => 
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => 
{
    options.Authority = "https://localhost:5001";
    options.RequireHttpsMetadata = true;
    options.ClientId = "oidcClient";
    options.ClientSecret = "secret";

    options.ResponseType = "code";
    options.UsePkce = true;
    options.ResponseMode = "query";

    options.Scope.Add("offline_access");
    options.Scope.Add("roles");
    
    options.SaveTokens = true;
});

public async Task<IActionResult> Logout()
{
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);

    return new SignOutResult(new[] { OpenIdConnectDefaults.AuthenticationScheme, CookieAuthenticationDefaults.AuthenticationScheme });
}
my WebApp HomeController中的注销方法如下所示:

// Authorization Code + PKCE Flow
new Client
{
    ClientId = "oidcClient",
    ClientName = "Example App",
    ClientSecrets = { new Secret("secret".Sha256()) },

    RedirectUris = { "https://localhost:44301/signin-oidc" },
    PostLogoutRedirectUris = { "https://localhost:44301/signout-callback-oidc" },

    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = true,
    RequireClientSecret = true,
    
    AllowedScopes = 
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email,
        IdentityServerConstants.StandardScopes.OfflineAccess,
        "roles",
    },

    AllowPlainTextPkce = false,
},

services.AddAuthentication(options => 
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => 
{
    options.Authority = "https://localhost:5001";
    options.RequireHttpsMetadata = true;
    options.ClientId = "oidcClient";
    options.ClientSecret = "secret";

    options.ResponseType = "code";
    options.UsePkce = true;
    options.ResponseMode = "query";

    options.Scope.Add("offline_access");
    options.Scope.Add("roles");
    
    options.SaveTokens = true;
});

public async Task<IActionResult> Logout()
{
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);

    return new SignOutResult(new[] { OpenIdConnectDefaults.AuthenticationScheme, CookieAuthenticationDefaults.AuthenticationScheme });
}
public异步任务注销()
{
等待HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
等待HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
返回新的SignOutResult(新[]{OpenIdConnectDefaults.AuthenticationScheme,CookieAuthenticationDefaults.AuthenticationScheme});
}
IdentityServer4日志告诉我登录时=>login Success和注销时=>Logout Success

这很奇怪-应用程序始终保持登录状态。

当我注销并返回到WebApp主页索引页时,我仍在登录-尽管我应该注销

您知道如何在IdentityServer4 OIDC应用程序中正确配置注销吗


您知道如何解决此问题吗?

注销方法不应返回任何内容。因为如果这样做,就会覆盖签出方法在内部生成的重定向

更好的方法是:

public async Task DoLogout()
{
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
}

谢谢,这是一个非常好的提示-您的代码运行得非常好!实际上,在我的特殊情况下,当我将ASP.NET标识与EF核心用户存储一起使用时,错误似乎仍然会发生,但内存中的TestUser没有问题。。。我需要调查一下:)也许是饼干混合的问题?请注意,identity server有自己的cookie集,而客户端有自己的cookie集……是的,情况就是这样;)