求IdentityServer4与Asp.net Core 2.0的Backchannel登出示例
很高兴听到你已经顺利搞定了IdentityServer4和ASP.NET Core 2.0的Front Channel登出!针对你问的Backchannel登出实现,我来给你一个可运行的示例,还有关于BackChannelLogoutUri的明确说明:
Backchannel登出完整实现步骤
1. IdentityServer4客户端配置
首先在IDS4的客户端配置中,指定BackChannelLogoutUri和相关属性:
new Client { ClientId = "your-client-app-id", ClientName = "Your Client Application", // 基础配置(授权类型、重定向URI等) AllowedGrantTypes = GrantTypes.Code, RedirectUris = new List<string> { "https://your-client-app.com/signin-oidc" }, PostLogoutRedirectUris = new List<string> { "https://your-client-app.com/signout-callback-oidc" }, ClientSecret = new Secret("your-client-secret".Sha256()), // Backchannel登出核心配置 BackChannelLogoutUri = "https://your-client-app.com/api/signout-backchannel", BackChannelLogoutSessionRequired = true, // 可选,默认true,仅当用户有活跃会话时触发登出 AllowOfflineAccess = true // 如果需要持久化会话,开启这个 }
这里的BackChannelLogoutUri就是你的ASP.NET Core客户端接收IDS4登出通知的接口地址,接下来我们要在客户端实现这个接口。
2. ASP.NET Core 2.0客户端端处理
2.1 配置认证服务
在Startup.cs的ConfigureServices中,确保OpenID Connect认证支持Backchannel登出的事件处理:
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.IdentityModel.Tokens; public void ConfigureServices(IServiceCollection services) { // 添加身份认证 services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(options => { options.Authority = "https://your-ids4-server-url"; options.ClientId = "your-client-app-id"; options.ClientSecret = "your-client-secret"; options.ResponseType = "code"; options.SaveTokens = true; // 处理远程登出事件,清除本地用户会话 options.Events = new OpenIdConnectEvents { OnRemoteSignOut = async context => { await context.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); context.HandleResponse(); } }; }); // 其他服务配置... services.AddControllersWithViews(); }
2.2 实现Backchannel登出接收接口
创建一个API控制器来接收IDS4发送的logout_token,并完成会话清理:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Identity; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Threading.Tasks; [Route("api/[controller]")] [ApiController] public class SignoutBackchannelController : ControllerBase { private readonly SignInManager<IdentityUser> _signInManager; private readonly IConfiguration _configuration; public SignoutBackchannelController(SignInManager<IdentityUser> signInManager, IConfiguration configuration) { _signInManager = signInManager; _configuration = configuration; } [HttpPost] public async Task<IActionResult> Post([FromForm] string logout_token) { if (string.IsNullOrWhiteSpace(logout_token)) { return BadRequest("Logout token is missing"); } // 验证logout_token的有效性(关键步骤,防止恶意请求) var validationParams = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = _configuration["Auth:Authority"], // 从配置文件读取IDS4地址 ValidateAudience = true, ValidAudience = _configuration["Auth:ClientId"], // 读取客户端ID ValidateLifetime = true, // 从IDS4的元数据端点获取公钥,或者直接配置 IssuerSigningKeys = await GetIdentityServerSigningKeysAsync() }; try { var tokenHandler = new JwtSecurityTokenHandler(); tokenHandler.ValidateToken(logout_token, validationParams, out var validatedToken); // 提取会话ID(sid声明) var jwtToken = validatedToken as JwtSecurityToken; var sessionId = jwtToken?.Claims.FirstOrDefault(c => c.Type == "sid")?.Value; if (!string.IsNullOrWhiteSpace(sessionId)) { // 清除当前会话对应的用户登录状态 // 如果是多实例部署,需要确保会话状态共享(比如使用Redis分布式缓存) await _signInManager.SignOutAsync(); } return Ok(); } catch (SecurityTokenException ex) { return BadRequest($"Invalid logout token: {ex.Message}"); } } // 辅助方法:从IDS4元数据端点获取签名公钥 private async Task<IEnumerable<SecurityKey>> GetIdentityServerSigningKeysAsync() { var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>( $"{_configuration["Auth:Authority"]}/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever()); var config = await configurationManager.GetConfigurationAsync(CancellationToken.None); return config.SigningKeys; } }
3. 关键注意事项
- Token验证不可省略:必须验证
logout_token的签发者、受众、有效期和签名,避免恶意请求导致的非法登出。 - 会话状态共享:如果你的客户端是多实例部署,需要使用分布式会话存储(比如Redis),这样Backchannel登出通知能在所有实例上生效。
- IDS4的Backchannel行为:当用户在IDS4发起全局登出时,IDS4会遍历所有配置了
BackChannelLogoutUri的客户端,发送POST请求携带logout_token,触发客户端的会话清理。
关于BackChannelLogoutUri的指向
简单来说,这个URI就是你在ASP.NET Core客户端中实现的那个POST接口地址,也就是上面示例中的https://your-client-app.com/api/signout-backchannel,IDS4会通过这个地址把登出通知发送给你的客户端。
内容的提问来源于stack exchange,提问作者MaxT
相关产品推荐
相关产品推荐

