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

如何扩展Micronaut CustomJWTClaimsSetGenerator返回全部用户属性

JWT认证扩展返回自定义用户属性实现方案

现有代码基础

1. CustomDelegatingAuthenticationProvider 类

@Singleton
@Replaces(value = DelegatingAuthenticationProvider.class)
public class CustomDelegatingAuthenticationProvider extends DelegatingAuthenticationProvider {
    /**
     * @param userFetcher        从持久层拉取用户信息
     * @param passwordEncoder    用于校验明文密码与加密密码是否匹配
     * @param authoritiesFetcher 拉取指定用户的权限集合
     */
    public CustomDelegatingAuthenticationProvider(UserFetcher userFetcher, PasswordEncoder passwordEncoder, AuthoritiesFetcher authoritiesFetcher) {
        super(userFetcher, passwordEncoder, authoritiesFetcher);
    }

    @Override
    protected Publisher<AuthenticationResponse> createSuccessfulAuthenticationResponse(AuthenticationRequest authenticationRequest, UserState userState) {

        if (userState instanceof UserMember) {
            UserMember user = (UserMember) userState;
            return Flowable
                    .fromPublisher(authoritiesFetcher.findAuthoritiesByUsername(user.getUsername()))
                    .map(authorities -> new HDSUser(user.getUsername(), authorities, user.getId()));
        }
        return super.createSuccessfulAuthenticationResponse(authenticationRequest, userState);
    }
}

2. CustomJWTClaimsSetGenerator 类

@Singleton
@Replaces(value = JWTClaimsSetGenerator.class)
public class CustomJWTClaimsSetGenerator extends JWTClaimsSetGenerator {

    CustomJWTClaimsSetGenerator(TokenConfiguration tokenConfiguration, @Nullable JwtIdGenerator jwtIdGenerator, @Nullable ClaimsAudienceProvider claimsAudienceProvider) {
        super(tokenConfiguration, jwtIdGenerator, claimsAudienceProvider);
    }

    protected void populateWithUserDetails(JWTClaimsSet.Builder builder, UserDetails userDetails) {
        super.populateWithUserDetails(builder, userDetails);

        if (userDetails instanceof HDSUser) {
            builder.claim("userId", ((HDSUser) userDetails).getId());
        }
    }

}

3. HDSUser 自定义用户类

@CompileStatic
public class HDSUser  extends UserDetails {

    private long id;

    public HDSUser(String username, Collection<String> roles, long id) {
        super(username, roles);
        this.id = id;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
}

需求说明

当前JWT认证成功后返回给客户端的响应仅包含用户名,需要额外返回用户ID等自定义用户属性。


实现方案

按你需要返回属性的场景选择对应修改方式:

场景1:自定义属性写入JWT Token载荷

你现有的CustomJWTClaimsSetGenerator已经实现了userId写入JWT载荷的逻辑,如果需要新增更多用户属性,按以下步骤操作:

  1. 在HDSUser类中新增对应成员变量,以及对应的getter、setter方法,示例新增手机号字段:
@CompileStatic
public class HDSUser  extends UserDetails {
    private long id;
    // 新增手机号字段
    private String phone;

    public HDSUser(String username, Collection<String> roles, long id, String phone) {
        super(username, roles);
        this.id = id;
        this.phone = phone;
    }

    // 原有getter setter省略
    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}
  1. 修改CustomJWTClaimsSetGenerator的populateWithUserDetails方法,追加自定义字段写入逻辑:
protected void populateWithUserDetails(JWTClaimsSet.Builder builder, UserDetails userDetails) {
    super.populateWithUserDetails(builder, userDetails);
    if (userDetails instanceof HDSUser) {
        HDSUser hdsUser = (HDSUser) userDetails;
        builder.claim("userId", hdsUser.getId());
        // 追加手机号字段
        builder.claim("phone", hdsUser.getPhone());
    }
}

注意:不要将密码、身份证号等敏感信息写入JWT载荷,JWT仅做Base64编码,明文可直接解析。

场景2:自定义属性直接在认证接口响应体返回

如果不需要把属性放到Token里,只需要在/login等认证接口的响应体中直接返回给客户端,修改CustomDelegatingAuthenticationProvider的createSuccessfulAuthenticationResponse方法,使用AuthenticationResponse.success的带附加属性重载方法即可:

@Override
protected Publisher<AuthenticationResponse> createSuccessfulAuthenticationResponse(AuthenticationRequest authenticationRequest, UserState userState) {
    if (userState instanceof UserMember) {
        UserMember user = (UserMember) userState;
        return Flowable
                .fromPublisher(authoritiesFetcher.findAuthoritiesByUsername(user.getUsername()))
                .map(authorities -> {
                    HDSUser hdsUser = new HDSUser(user.getUsername(), authorities, user.getId(), user.getPhone());
                    // 组装要返回的自定义属性
                    Map<String, Object> extAttrs = new HashMap<>();
                    extAttrs.put("userId", hdsUser.getId());
                    extAttrs.put("phone", hdsUser.getPhone());
                    // 生成带自定义属性的认证成功响应
                    return AuthenticationResponse.success(hdsUser.getUsername(), extAttrs, hdsUser);
                });
    }
    return super.createSuccessfulAuthenticationResponse(authenticationRequest, userState);
}

补充说明

如果需要后续请求解析JWT时,能直接从上下文拿到完整的HDSUser对象,你需要额外自定义TokenAuthenticationFetcher实现类,从JWT的载荷中取出自定义字段,重新组装成HDSUser对象注入到请求上下文。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 23:15:03