IdentityServer:如何为客户端凭据令牌添加user_id额外声明?
在IdentityServer4的Client Credentials令牌中添加自定义user_id声明
首先得明确一个关键点:Client Credentials(客户端凭证)流本身是基于客户端身份的认证,而非用户身份,所以默认生成的令牌里只会包含客户端相关的信息(比如受众、作用域、过期时间),不会有用户类声明。要把动态传递的user_id塞进令牌里,需要在IdentityServer4端做扩展配置,同时调整客户端的请求方式。
具体解决方案步骤
1. 在IdentityServer4中实现自定义令牌请求验证器
我们需要创建一个自定义验证器,用来读取请求中的user_id参数,并把它添加到令牌的声明集合中:
public class CustomTokenRequestValidator : ICustomTokenRequestValidator { public Task ValidateAsync(CustomTokenRequestValidationContext context) { // 从原始请求参数中提取user_id if (context.Result.ValidatedRequest.Raw.TryGetValue("user_id", out var userId)) { // 将user_id添加到客户端声明中(Client Credentials流中用客户端声明承载自定义信息) context.Result.ValidatedRequest.ClientClaims.Add(new Claim("user_id", userId)); } return Task.CompletedTask; } }
然后在IdentityServer4的Startup.cs中注册这个服务,让IdentityServer启用这个自定义验证逻辑:
services.AddIdentityServer() // 保留你原有的配置(比如AddInMemoryClients、AddInMemoryApiScopes等) .AddCustomTokenRequestValidator<CustomTokenRequestValidator>();
2. 配置ApiScope允许user_id声明
确保你的ApiScope配置中包含user_id作为允许的声明,这样IdentityServer才会把它包含在access token里:
new ApiScope("your-api-scope-name", "Your API Display Name") { UserClaims = { "user_id" } };
3. 调整客户端请求代码(IdentityServer3 TokenClient)
你之前尝试的RequestClientCredentialsAsync传递额外参数的方式是可行的,但也可以用RequestAsync直接构造完整的请求参数,确保user_id被正确发送:
var client = new TokenClient(requestPath, CLIENT_ID, CLIENT_SECRET, AuthenticationStyle.PostValues); var requestParams = new Dictionary<string, string> { { "grant_type", "client_credentials" }, { "scope", apiScope }, { "user_id", "123123" } // 这里替换为实际从数据库获取的用户ID }; var tokenResponse = await client.RequestAsync(requestParams).ConfigureAwait(false);
4. 验证结果
现在获取到的access token应该已经包含user_id声明了。你可以用JWT解码工具(比如本地的解码逻辑或者在线工具)检查令牌内容,确认user_id是否存在。
注意事项
- 虽然可以在Client Credentials流中添加用户声明,但要确保业务逻辑合理:这个客户端必须被授权可以代表指定用户执行操作,避免权限滥用。
- 确保IdentityServer4的客户端配置中,
AllowedScopes包含你指定的apiScope,并且客户端的ClientId和ClientSecret配置正确。 - 如果你的目标API(网站B的REST接口)需要验证
user_id声明,要确保API的认证配置能正确读取这个声明。
内容的提问来源于stack exchange,提问作者Evan
相关产品推荐
相关产品推荐

