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

如何在Spring Boot服务生成的JWT令牌中添加额外自定义字段?

问题1解答

教程中基于UserDetails生成JWT是Spring Security体系下的常规实现逻辑,核心原因有两个:

  • UserDetails是Spring Security内置的标准用户信息接口,整个身份校验、权限拦截的默认流程都基于这个接口实现,直接使用它不需要额外改造Spring Security的原生验证链路,能减少冗余代码,降低适配成本。
  • 实现业务层和安全层的解耦,业务UserDTO可能会随着需求迭代频繁修改字段,而安全层依赖的UserDetails核心方法稳定,不会因为业务字段调整影响安全链路的逻辑。
    当然你完全可以直接用UserDTO生成令牌,只是需要自己补充适配Spring Security验证流程的相关代码,教程的写法是兼顾通用性和可维护性的最优选择。

问题2解答

有两种成熟的实现方案可以把额外信息写入JWT:

方案1:自定义UserDetails实现类

不用Spring Security自带的org.springframework.security.core.userdetails.User实现,自己编写类实现UserDetails接口,在类中新增你需要的额外字段即可,示例代码如下:

public class CustomUserDetails implements UserDetails {
    // Spring Security要求的标准字段
    private String username;
    private String password;
    private Collection<? extends GrantedAuthority> authorities;
    // 自定义额外字段
    private Long userId;
    private String userNickname;

    // 构造方法,传入UserDTO填充所有字段
    public CustomUserDetails(User user) {
        this.username = user.getEMail();
        this.password = user.getPswd();
        // 填充权限的逻辑和原有代码一致
        this.authorities = user.getUserTypes().stream()
                .map(UserType::getOperations)
                .flatMap(Set::stream)
                .map(op -> new SimpleGrantedAuthority(op.getName()))
                .distinct()
                .collect(Collectors.toList());
        // 填充自定义字段
        this.userId = user.getId();
        this.userNickname = user.getNickname();
    }

    // 实现UserDetails接口的所有抽象方法,不需要校验的字段(如账号过期、锁定等)直接返回true即可
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }
    @Override
    public String getPassword() {
        return password;
    }
    @Override
    public String getUsername() {
        return username;
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return true;
    }
    // 额外字段的getter方法
    public Long getUserId() {
        return userId;
    }
    public String getUserNickname() {
        return userNickname;
    }
}

之后修改loadUserByUsername方法,直接返回你自定义的CustomUserDetails实例:

@Override
public UserDetails loadUserByUsername(String UserId) throws UsernameNotFoundException {
    // 原有参数校验、查询User的逻辑不变
    User user = this.GetHttpValue(UserId);
    // 直接返回自定义的UserDetails实例
    return new CustomUserDetails(user);
}

最后修改doGenerateToken方法,把自定义字段写入JWT:

private String doGenerateToken(Map<String, Object> claims, UserDetails userDetails) {
    final Date createdDate = clock.now();
    final Date expirationDate = calculateExpirationDate(createdDate);
    // 强转为自定义类型获取额外字段
    CustomUserDetails customUser = (CustomUserDetails) userDetails;

    return Jwts.builder()
            .setClaims(claims)
            .setSubject(customUser.getUsername())
            .claim("authorities", customUser.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
            // 写入自定义字段
            .claim("userId", customUser.getUserId())
            .claim("userNickname", customUser.getUserNickname())
            .setIssuedAt(createdDate)
            .setExpiration(expirationDate)
            .signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret().getBytes())
            .compact();
}

方案2:直接使用claims参数传值

如果你只需要临时加少量字段,不需要改造UserDetails,可以直接把额外字段塞入doGenerateToken的第一个入参claims中,setClaims方法会自动把所有Map中的键值对写入JWT payload:

// 调用doGenerateToken之前填充自定义字段
Map<String, Object> extraClaims = new HashMap<>();
extraClaims.put("userId", user.getId());
extraClaims.put("userNickname", user.getNickname());
// 调用生成方法
String token = doGenerateToken(extraClaims, userDetails);

注意:JWT的payload是Base64编码的明文,不要写入密码、身份证号等敏感信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 22:54:04