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

Spring OAuth2资源服务:如何将Jwt转换为自定义MyUser认证主体

问题描述

当前已配置Spring Security的SecurityFilterChain,OAuth2资源服务器部分配置如下:

.oauth2ResourceServer(resourceServerConfigurer -> {
    resourceServerConfigurer.jwt(jwtConfigurer -> {
        final var jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(myJwtGrantedAuthoritiesMapper);
        jwtConfigurer.jwtAuthenticationConverter(jwtAuthenticationConverter);
    });
})
.authorizeHttpRequests(requests -> requests.anyRequest().authenticated());

当前配置运行正常,可通过SecurityContextHolder.getAuthentication().getPrincipal()获取Jwt实例,再通过jwt.getClaimAsString("given_name")等方法获取用户信息。

希望将Jwt中的部分数据映射到自定义的MyUser类,使认证主体变为MyUser实例,避免直接操作Jwt对象。请问如何实现将JwtAuthenticationToken/Jwt转换为以MyUser为主体的认证令牌?

解决方案

核心思路是自定义JWT认证转换器,替换默认的JwtAuthenticationConverter,在转换器中完成Jwt到MyUser的映射,并生成以MyUser为主体的认证令牌。

步骤1:定义自定义MyUser类

先创建封装用户信息的MyUser类,按需添加需要从JWT中提取的字段:

public class MyUser {
    private String userId;
    private String givenName;
    private String familyName;

    // 构造方法
    public MyUser(String userId, String givenName, String familyName) {
        this.userId = userId;
        this.givenName = givenName;
        this.familyName = familyName;
    }

    // 省略getter/setter方法
}

步骤2:自定义JWT认证转换器

继承JwtAuthenticationConverter并重写createJwtAuthenticationToken方法,在方法中完成Jwt到MyUser的转换:

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import java.util.Collection;
import java.util.function.Function;

public class CustomJwtAuthenticationConverter extends JwtAuthenticationConverter {

    private final Function<Jwt, Collection<GrantedAuthority>> authoritiesConverter;

    public CustomJwtAuthenticationConverter(Function<Jwt, Collection<GrantedAuthority>> authoritiesConverter) {
        this.authoritiesConverter = authoritiesConverter;
    }

    @Override
    protected JwtAuthenticationToken createJwtAuthenticationToken(Jwt jwt, Collection<GrantedAuthority> authorities) {
        // 从JWT中提取字段,构造MyUser实例
        String userId = jwt.getClaimAsString("sub");
        String givenName = jwt.getClaimAsString("given_name");
        String familyName = jwt.getClaimAsString("family_name");
        MyUser myUser = new MyUser(userId, givenName, familyName);

        // 返回以MyUser为主体的JwtAuthenticationToken
        return new JwtAuthenticationToken(jwt, authorities, myUser);
    }
}

注:JwtAuthenticationToken的第三个参数即为认证主体,传入MyUser实例即可,同时保留原始Jwt对象作为第一个参数,方便后续可能的额外操作。

步骤3:替换Security配置中的转换器

在原有的SecurityFilterChain配置中,使用自定义转换器替换默认实现:

.oauth2ResourceServer(resourceServerConfigurer -> {
    resourceServerConfigurer.jwt(jwtConfigurer -> {
        // 实例化自定义转换器,传入已有的权限转换器
        final var customJwtConverter = new CustomJwtAuthenticationConverter(myJwtGrantedAuthoritiesMapper);
        jwtConfigurer.jwtAuthenticationConverter(customJwtConverter);
    });
})
.authorizeHttpRequests(requests -> requests.anyRequest().authenticated());

步骤4:验证结果

配置完成后,通过SecurityContextHolder获取的认证主体即为MyUser实例,可直接调用其方法获取信息:

MyUser currentUser = (MyUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String userName = currentUser.getGivenName();

可选:自定义认证令牌类

如果不想使用JwtAuthenticationToken,可以自定义继承AbstractAuthenticationToken的令牌类:

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import java.util.Collection;

public class MyUserAuthenticationToken extends AbstractAuthenticationToken {
    private final MyUser principal;
    private final Jwt jwt;

    public MyUserAuthenticationToken(MyUser principal, Jwt jwt, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.jwt = jwt;
        setAuthenticated(true);
    }

    @Override
    public Object getCredentials() {
        return jwt;
    }

    @Override
    public Object getPrincipal() {
        return principal;
    }
}

然后在自定义转换器的createJwtAuthenticationToken方法中返回该令牌即可:

@Override
protected JwtAuthenticationToken createJwtAuthenticationToken(Jwt jwt, Collection<GrantedAuthority> authorities) {
    MyUser myUser = new MyUser(jwt.getClaimAsString("sub"), jwt.getClaimAsString("given_name"), jwt.getClaimAsString("family_name"));
    return new MyUserAuthenticationToken(myUser, jwt, authorities);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:19:56