Spring Authorization Server无法访问java.time.Instant#seconds字段问题求助
解决方案:替换Nimbus依赖的Gson实现为Jackson
问题根源
Spring Boot 3.x + Java 17的模块系统下,Nimbus JOSE使用的shaded版Gson无法通过反射访问java.time.Instant的私有字段,且由于类加载隔离问题,你之前尝试的自定义TypeAdapter、模块权限开放方案均无法生效。Jackson作为Spring生态默认的JSON处理库,对Java模块系统的适配更完善,能彻底解决该问题。
具体步骤
1. 排除默认依赖中的Gson版本
Maven(pom.xml)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId> <exclusions> <exclusion> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> </exclusion> </exclusions> </dependency>
Gradle(build.gradle)
implementation('org.springframework.boot:spring-boot-starter-oauth2-authorization-server') { exclude group: 'com.nimbusds', module: 'nimbus-jose-jwt' }
2. 添加Jackson适配的Nimbus依赖
选择与Spring Boot 3.3.1兼容的版本(可通过项目dependencyManagement确认具体版本):
Maven
<dependency> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> <version>9.37.3</version> <exclusions> <exclusion> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt-jackson</artifactId> <version>9.37.3</version> </dependency>
Gradle
implementation('com.nimbusds:nimbus-jose-jwt:9.37.3') { exclude group: 'com.google.code.gson', module: 'gson' } implementation 'com.nimbusds:nimbus-jose-jwt-jackson:9.37.3'
3. 配置JWT编码器使用Jackson
创建配置类,指定Nimbus编码器使用Jackson作为JSON处理器:
import com.nimbusds.jose.jackson.josec.JOSEObjectMapper; import com.nimbusds.jose.proc.SecurityContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.jwt.JwtEncoder; import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; import org.springframework.security.oauth2.jwt.JWKSource; @Configuration public class JwtConfig { @Bean public JwtEncoder jwtEncoder(JWKSource<SecurityContext> jwkSource) { NimbusJwtEncoder encoder = new NimbusJwtEncoder(jwkSource); encoder.setJOSEObjectMapper(new JOSEObjectMapper()); return encoder; } }
备选方案(不替换依赖)
如果不想调整依赖,可在自定义JWT声明时避免直接传入Instant对象,将其转换为兼容的类型:
@Component public class CustomJwtTokenCustomizer implements OAuth2TokenCustomizer<JwtEncodingContext> { @Override public void customize(JwtEncodingContext context) { UserInfoEntity user = (UserInfoEntity) context.getPrincipal().getPrincipal(); // 错误写法:直接放入Instant // context.getClaims().claim("last_login", user.getLastLogin()); // 正确写法1:转换为时间戳 context.getClaims().claim("last_login", user.getLastLogin().toEpochMilli()); // 正确写法2:转换为ISO格式字符串 // context.getClaims().claim("last_login", user.getLastLogin().toString()); } }
内容的提问来源于stack exchange,提问作者Abhishek Singh
相关产品推荐
相关产品推荐

