You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IdentityServer4刷新令牌时身份声明丢失问题咨询

问题分析与解答

一、IdentityServer4中ProfileService接收的Claims Identity构造逻辑

IdentityServer4处理令牌刷新请求时,不会触发完整的Asp.Net Core登录流程,而是直接从关联的用户会话数据中提取核心身份信息构造Subject:

  • 刷新请求验证通过后,IdentityServer会读取与该刷新令牌绑定的用户会话,仅提取sub(用户唯一标识)这类核心声明来初始化Subject。
  • 这个Subject的Claims集合,只包含IdentityServer认定为用户基础身份的数据,也就是首次登录时存入自身会话的核心声明,并非经过IClaimsTransformation转换后的完整集合。

二、ProfileService无法获取IClaimsTransformation声明的原因

IClaimsTransformation和IdentityServer的令牌生成流程属于两个独立的执行链路:

  • IClaimsTransformation是Asp.Net Core Authentication中间件的一部分,仅在完整登录请求(比如首次调用SignInAsync)或访问Asp.Net Core授权保护资源时,才会对当前请求的Principal做转换。
  • 令牌刷新请求属于IdentityServer的令牌端点操作,处理时不会走完整的Asp.Net Core身份验证管道,自然不会执行IClaimsTransformation的TransformAsync方法。你在TransformAsync中看到的声明,是其他请求场景下的结果,和刷新令牌流程无关。

另外,你通过HttpContext.SignInAsync(issuer)添加的AdditionalClaims,如果未配置为持久化到IdentityServer用户会话,刷新时也无法被读取。默认情况下,这些额外声明仅在首次生成身份令牌时被包含,若未标记为会话持久化内容,刷新流程不会主动加载。

三、可行的解决方法

  1. 在ProfileService中主动加载声明
    不要依赖IClaimsTransformation,直接在自定义ProfileService的GetProfileDataAsync方法中,从数据源(如数据库、用户存储)加载所需声明并添加到输出集合:

    public class CustomProfileService : DefaultProfileService
    {
        private readonly IUserRepository _userRepository;
    
        public CustomProfileService(IUserRepository userRepository, ILogger<DefaultProfileService> logger) 
            : base(logger)
        {
            _userRepository = userRepository;
        }
    
        public override async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            await base.GetProfileDataAsync(context);
            
            // 根据用户ID加载额外声明
            var userId = context.Subject.GetSubjectId();
            var additionalClaims = await _userRepository.GetUserAdditionalClaims(userId);
            
            context.IssuedClaims.AddRange(additionalClaims);
        }
    }
    
  2. 将声明持久化到用户会话
    若希望首次登录的声明在刷新时复用,可在登录时通过AuthenticationProperties标记声明需要持久化:

    var authProps = new AuthenticationProperties
    {
        IsPersistent = true
    };
    // 也可手动指定要持久化的声明类型
    authProps.StoreTokens(new[] { new AuthenticationToken { Name = "custom_claims", Value = JsonConvert.SerializeObject(additionalLocalClaims) } });
    
    await HttpContext.SignInAsync(issuer, authProps);
    

    不过这种方式不如ProfileService主动加载可靠,会话存储的声明存在过期或丢失风险。

内容的提问来源于stack exchange,提问作者Merijn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 12:52:42