如何在IdentityServer4中配置多客户端以禁用单点登录?
如何在IdentityServer4中为特定客户端禁用单点登录(SSO)
当然可以实现!你可以通过调整客户端配置(无论是IdentityServer端的客户端定义,还是客户端应用的OpenID Connect设置),让已登录第一个客户端后,访问第二个客户端时仍需重新登录。下面是具体的实现方案:
方案1:在客户端配置中强制触发重新登录(推荐)
最直接的方式是利用OpenID Connect的prompt=login标准参数,它会告诉IdentityServer忽略当前的用户会话,强制用户重新输入凭据登录。你可以通过两种方式配置:
方式A:在客户端应用的OpenID Connect中间件中设置
如果你使用ASP.NET Core的OpenID Connect中间件,直接在客户端配置里指定Prompt = "login",就能让这个客户端每次请求授权时都强制重新登录:
services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.Authority = "https://your-identityserver-url"; options.ClientId = "your-second-client-id"; options.ClientSecret = "your-client-secret"; options.ResponseType = "code"; // 核心配置:强制每次都重新登录,禁用SSO options.Prompt = "login"; });
方式B:在IdentityServer端统一配置客户端规则
如果你希望在IdentityServer端统一管控这个行为,可以给需要禁用SSO的客户端添加自定义标记,再通过中间件自动注入prompt=login参数。
首先修改你的GetClients方法,为目标客户端添加自定义属性:
internal static IEnumerable<Client> GetClients(IEnumerable<RegisteredClient> clients) { return clients.Select(x => { var scopes = x.AllowedScopes.ToList(); scopes.Add(IdentityServerConstants.StandardScopes.OpenId); scopes.Add(IdentityServerConstants.StandardScopes.Profile); var client = new Client { ClientId = x.ClientId, ClientName = x.ClientName, ClientSecrets = { new Secret(x.ClientSecret.Sha256()) }, AllowedGrantTypes = GrantTypes.Code, RedirectUris = x.RedirectUris, PostLogoutRedirectUris = x.PostLogoutRedirectUris, AllowedScopes = scopes, // 添加标记:该客户端需要禁用SSO Properties = new Dictionary<string, string> { ["ForceLogin"] = "true" } }; // 可选:关闭离线访问,避免刷新令牌绕过重新登录 if (x.ClientId == "your-second-client-id") { client.AllowOfflineAccess = false; } return client; }); }
然后添加一个自定义中间件,在授权请求前检查标记并注入参数:
public class ForceLoginMiddleware { private readonly RequestDelegate _next; public ForceLoginMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context, IClientStore clientStore) { if (context.Request.Path.StartsWithSegments("/connect/authorize")) { var clientId = context.Request.Query["client_id"].FirstOrDefault(); if (!string.IsNullOrEmpty(clientId)) { var client = await clientStore.FindEnabledClientByIdAsync(clientId); if (client != null && client.Properties.TryGetValue("ForceLogin", out var forceLogin) && forceLogin == "true") { context.Request.QueryString = context.Request.QueryString.Add("prompt", "login"); } } } await _next(context); } } // 在Startup.cs中注册中间件(要放在UseIdentityServer之前) app.UseMiddleware<ForceLoginMiddleware>(); app.UseIdentityServer();
方案2:隔离客户端应用的认证Cookie
如果只是想让客户端应用的本地会话独立,你可以为每个客户端设置不同的认证Cookie名称,避免客户端之间共享会话:
services.AddAuthentication(options => { options.DefaultScheme = "SecondClientCookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("SecondClientCookies", options => { options.Cookie.Name = "SecondClient.Auth"; // 与第一个客户端的Cookie名称区分开 }) .AddOpenIdConnect("oidc", options => { // 其他配置... });
关键提示
prompt=login是OpenID Connect的标准参数,能彻底绕过IdentityServer的SSO会话,确保用户必须重新登录。- 如果客户端开启了
AllowOfflineAccess(获取刷新令牌),记得为禁用SSO的客户端关闭该选项,防止长期有效的刷新令牌绕过重新登录要求。
内容的提问来源于stack exchange,提问作者paranamix2
相关产品推荐
相关产品推荐

