如何在IdentityServer4中实现自定义grant type解决跨身份源API访问问题
实现方案
1. 核心思路说明
你提到的两个操作都是需要做的:实现IExtensionGrantValidator扩展授权验证,以及在保护API的IdentityServer(下称目标IdSvr)中信任原有登录用的IdentityServer(下称源IdSvr)的签名。
这个方案的本质是让目标IdSvr认可源IdSvr签发的用户身份凭证,给应用换发能访问当前域API的令牌,避免用户二次登录。
2. 具体实现步骤
2.1 源IdSvr侧配置
- 确保源IdSvr给应用签发的
id_token或者access_token包含足够的用户身份声明(比如sub、name、email等你需要传递的字段) - 导出源IdSvr的签名公钥(一般是JWKS格式的公钥,注意不要泄露私钥)
2.2 目标IdSvr侧实现
第一步:注册源IdSvr的签名密钥
把源IdSvr的签名公钥添加到目标IdSvr的信任签名密钥列表中,用于验证源IdSvr签发的令牌合法性,避免伪造的凭证被用于兑换令牌。
你可以直接在目标IdSvr启动时配置:
builder.Services.AddIdentityServer() // 原有其他配置 .AddValidationKey(sourceIdSvrPublicKey); // 这里传入你导出的源IdSvr公钥
第二步:实现IExtensionGrantValidator自定义授权验证
自定义扩展授权类型,比如命名为source_idsvr_token,验证逻辑如下:
- 接收应用传过来的源IdSvr签发的有效令牌
- 验证令牌的签名、有效期、签发者、受众等核心参数是否合法
- 从合法令牌中提取用户声明,构造目标IdSvr的用户身份
- 返回验证通过结果,生成目标IdSvr签发的access_token给应用
示例代码框架:
public class SourceIdSvrGrantValidator : IExtensionGrantValidator { public string GrantType => "source_idsvr_token"; private readonly ITokenValidator _tokenValidator; public SourceIdSvrGrantValidator(ITokenValidator tokenValidator) { _tokenValidator = tokenValidator; } public async Task ValidateAsync(ExtensionGrantValidationContext context) { var sourceToken = context.Request.Raw.Get("source_token"); if (string.IsNullOrEmpty(sourceToken)) { context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "missing source token"); return; } // 验证源IdSvr签发的令牌 var validationResult = await _tokenValidator.ValidateAccessTokenAsync(sourceToken); if (validationResult.IsError) { context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid source token"); return; } // 提取用户声明,构造目标域的用户身份 var claims = validationResult.Claims.ToList(); // 可以在这里按需添加、转换声明,适配目标IdSvr的业务要求 context.Result = new GrantValidationResult( subject: validationResult.Subject.FindFirst("sub").Value, authenticationMethod: "source_idsvr", claims: claims); } }
然后在目标IdSvr中注册这个验证器:
builder.Services.AddIdentityServer() // 原有其他配置 .AddExtensionGrantValidator<SourceIdSvrGrantValidator>();
另外还要在目标IdSvr的客户端配置中,给对应的应用开放这个自定义授权类型的使用权限。
2.3 应用侧适配
应用拿到源IdSvr的登录令牌后,向目标IdSvr发起令牌请求,使用自定义的source_idsvr_token授权类型,传入源令牌,兑换目标IdSvr的access_token,之后就可以用这个新令牌访问受保护的API。
3. 可选优化方案
如果两个身份服务器都是你可控的,也可以考虑用联邦身份认证的方式,把源IdSvr配置为目标IdSvr的外部身份提供商,用户跳转一次完成登录即可,不需要自定义扩展授权。不过这种方式适合用户还没在源IdSvr登录的场景,你当前已经有应用持有源IdSvr的有效令牌,用扩展授权的方式体验更好,不需要跳转。
内容的提问来源于stack exchange,提问作者MLV
相关产品推荐
相关产品推荐

