oauth2 jwt token 返回accessToken对象中携带用户字段信息

本文介绍了如何在OAuth2中扩展JWT Token,使其在返回的accessToken对象中包含用户字段如userId。首先,需要重写DefaultAccessTokenConverter、UserAuthenticationConverter和JwtAccessTokenConverter在服务器端的方法。然后,在资源服务器client端进行相应配置,确保userId能在accessToken中持久化。对比两种方法,方法二更优,因为它使得access_token中不仅包含userId,还能在accessToken对象中直接显示,且client端配置更为简洁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

oauth2 源码中用户信息只返回用户名称,现有需求要求返回userId,只能重写某些方法,server端和client端都要修改:

方法一、结果:userId 封装在token中,需要解析access_token才能看到,但是经测试发现,使用此方法之后refresh_token获取access_token时,自定义的字段都不见了,连自带的username也不见了,应该是要再重写refresh_token获取时的一些方法,暂未实现。

server:

1、重写 DefaultAccessTokenConverter.java的部分方法:

import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;

import java.util.HashMap;
import java.util.Map;

public class MyDefaultAccessTokenConverter extends DefaultAccessTokenConverter {

    private boolean includeGrantType;

    private String scopeAttribute = SCOPE;

    private String clientIdAttribute = CLIENT_ID;

    private MyUserAuthenticationConverter userTokenConverter = new MyUserAuthenticationConverter();

    public Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
        Map<String, Object> response = new HashMap<String, Object>();
        OAuth2Request clientToken = authentication.getOAuth2Request();

        if (!authentication.isClientOnly()) {
            response.putAll(userTokenConverter.convertUserAuthentication(authentication.getUserAuthentication()));
        } else {
            if (clientToken.getAuthorities()!=null && !clientToken.getAuthorities().isEmpty()) {
                response.put(MyUserAuthenticationConverter.AUTHORITIES,
                        AuthorityUtils.authorityListToSet(clientToken.getAuthorities()));
            }
        }

        if (token.getScope()!=null) {
            response.put(scopeAttribute, token.getScope());
        }
        if (token.getAdditionalInformation().containsKey(JTI)) {
            response.put(JTI, token.getAdditionalInformation().get(JTI));
        }

        if (token.getExpiration() != null) {
            response.put(EXP, token.getExpiration().getTime() / 1000);
        }

        if (includeGrantType && authentication.getOAuth2Request().getGrantType()!=null) {
            response.put(GRANT_TYPE, authentication.getOAuth2Request().getGrantType());
        }

        response.putAll(token.getAdditionalInformation());

        response.put(clientIdAttribute, clientToken.getClientId());
        if (clientToken.getResourceIds() != null && !clientToken.getResourceIds().isEmpty()) {
            response.put(AUD, clientToken.getResourceIds());
        }
        return response;
    }
}

2、重写  UserAuthenticationConverter.java的部分方法:

import com.langyatech.fcp.oauth.entity.OauthUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;

import java.util.LinkedHashMap;
import java.util.Map;

public class MyUserAuthenticationConverter implements UserAuthenticationConverter {

    @Override
    public Map<String, ?> convertUserAuthentication(Authentication authentication) {
        LinkedHashMap response = new LinkedHashMap();
        response.put("userId", ((OauthUser) authentication.getPrincipal()).getUserId());
        if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
            response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
        }
        return response;
    }

    @Override
    public org.springframework.security.core.Authentication extractAuthentication(Map<String, ?> map) {
        return null;
    }
}

3、重写 JwtAccessTokenConverter.java

import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.*;
import org.springframework.security.oauth2.common.*;
import org.springframework.security.oauth2.common.util.JsonParser;
import org.springframework.security.oauth2.common.util.JsonParserFactory;
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import java.util.Map;

public class MyJwtAccessTokenConverter extends JwtAccessTokenConverter
{

    private AccessTokenConverter tokenConverter = new MyDefaultAccessTokenConverter();

    private JsonParser objectMapper = JsonParserFactory.create();

    private String verifierKey = new RandomValueStringGenerator().
<think>好的,我现在要回答用户的问题:“OAuth2AccessToken accessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody(); 是生成的jwttoken吗?” 首先,我需要理解这段代码的作用。用户是在使用Spring Security OAuth2框架中的tokenEndpoint来获取访问令牌。代码中的postAccessToken方法可能是在向OAuth2令牌端点发送请求,然后获取响应体中的accessToken。 接下来,用户想知道这个accessToken是否是JWT类型的令牌。这里需要明确OAuth2访问令牌的类型和生成方式。OAuth2支持多种令牌格式,包括不透明令牌(随机字符串)和JWT(结构化令牌)。具体生成的类型取决于服务器的配置。 在Spring Security OAuth2中,默认情况下,访问令牌可能是不透明令牌,但可以通过配置JwtTokenStore来使用JWT。因此,需要查看服务器端的配置,比如是否使用了JwtAccessTokenConverter。如果有配置,那么生成的令牌会是JWT,否则可能是不透明的。 另外,用户可能对JWT的结构和优势不太清楚,需要简要说明JWT包含头部、载荷和签名,以及其自包含和可验证的特点。同时,需要指出如何判断生成的令牌是否是JWT,比如检查令牌内容是否由三部分组成,用点分隔,或者解码后查看是否存在JSON结构。 还需要考虑用户可能的背景,他们可能在使用Spring框架进行OAuth2的集成,或者在开发需要安全认证的应用程序。因此,回答需要结合代码示例和配置说明,帮助用户理解如何确定他们的accessToken类型,并指导他们如何配置服务器以生成JWT。 总结起来,回答应该分几个部分:解释代码的作用,说明OAuth2访问令牌的类型,指出依赖服务器配置,给出判断方法,以及配置生成JWT的方法。同时,语言需要简洁明了,避免技术术语过多,必要时提供示例代码或配置片段。</think>在Spring Security OAuth2框架中,`tokenEndpoint.postAccessToken()` 生成的 `OAuth2AccessToken` **不一定是JWT Token**,具体取决于服务端配置。以下是关键分析: --- ### **1. 代码行为解析** ```java OAuth2AccessToken accessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody(); ``` - **作用**:调用OAuth2协议的`/oauth/token`端点,获取访问令牌。 - **默认行为**:若未显式配置JWT,Spring Security OAuth2默认生成的是**不透明令牌(Opaque Token)**,即一个随机字符串,需通过`/oauth/check_token`端点反向查询其元数据。 --- ### **2. JWT Token的生成条件** 需满足以下配置之一: #### **方案1:配置`JwtAccessTokenConverter`** ```java @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("your-secret-key"); // 对称密钥签名 // 或使用非对称密钥 // converter.setKeyPair(keyPair()); return converter; } ``` #### **方案2:使用`JWK`(JSON Web Key)** ```yaml # 在配置文件中启用JWT security: oauth2: resourceserver: jwt: jwk-set-uri: https://your-auth-server/.well-known/jwks.json ``` --- ### **3. 判断当前Token类型** #### **方法1:打印Token结构** ```java System.out.println(accessToken.getValue()); ``` - **JWT特征**:形如 `xxxxx.yyyyy.zzzzz`(三段式结构,Header、Payload、Signature用`.`分隔)。 - **Opaque特征**:无`.`分隔的随机字符串,如 `d9d4f7e0-3d9a-4a5b-932d-8d8a3c1d1e7e`。 #### **方法2:解码验证** ```java // 若为JWT,可尝试解码 String[] chunks = token.split("\\."); String header = new String(Base64.getUrlDecoder().decode(chunks[0])); String payload = new String(Base64.getUrlDecoder().decode(chunks[1])); System.out.println("Header: " + header); // 应显示算法、类型(如{"alg":"HS256","typ":"JWT"}) System.out.println("Payload: " + payload); // 应包含用户信息、权限等JSON数据 ``` --- ### **4. JWT vs Opaque Token对比** | **特性** | **JWT** | **Opaque Token** | |----------------|----------------------------------|---------------------------------| | **数据结构** | 自包含(Header+Payload+Signature) | 无意义字符串 | | **验证方式** | 本地验签(无需查认证服务器) | 必须调用`/oauth/check_token`端点 | | **性能** | 高(无网络IO) | 低(依赖远程调用) | | **适用场景** | 分布式系统、无状态架构 | 简单内部系统 | --- ### **5. 强制生成JWT的配置示例** ```java @Configuration @EnableAuthorizationServer public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints.accessTokenConverter(accessTokenConverter()); } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("my-secret-key-12345"); // 对称密钥 return converter; } } ``` 配置后,`postAccessToken()`将生成符合JWT标准的Token。 --- ### **结论** - 若代码中未显式配置JWT转换器,默认生成的是**不透明令牌**。 - JWT需要主动配置(如`JwtAccessTokenConverter`),其核心价值是**自包含性**和**无状态验证**。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值