Kotlin Spring Boot:TestRestTemplate+OAuth2测试权限上下文传递失败
问题解决:TestRestTemplate调用OAuth2接口时SecurityContext无认证信息
问题根源
你遇到的An Authentication object was not found in the SecurityContext异常,核心原因:
TestRestTemplate发送的是真实HTTP请求,测试代码中通过@WithMockUser或手动设置SecurityContext的操作仅在测试线程生效,但应用程序处理请求是独立的业务线程,线程绑定的SecurityContext无法跨线程传递。@WithMockUser是为普通表单登录场景设计的,无法适配OAuth2的JWT认证逻辑。
修复方案
方案1:使用Spring Security OAuth2测试注解(推荐)
Spring Security 5.3+提供@WithMockJwtAuthentication注解,专门用于模拟JWT认证请求,可直接将认证信息注入请求的SecurityContext:
import org.springframework.security.test.context.support.WithMockJwtAuthentication @Test @WithMockJwtAuthentication( authorities = ["SCOPE_write"], claims = ["someClaim" to "someClaimValue"] // 模拟JWT自定义Claims ) fun `update`() { val url = "http://localhost:${port}${basePath}/update" val headers = HttpHeaders() val body = HttpEntity( UpdateRequest( // 请求对象参数 ), headers ) val response = restTemplate.exchange( url, HttpMethod.PUT, body, typeReference<SomeResponseType>() ) }
方案2:手动添加Bearer Token到请求头
若需更灵活的JWT模拟,可手动生成合法Token并添加到请求头:
- 引入JJWT依赖(若未添加):
// build.gradle.kts dependencies { testImplementation("io.jsonwebtoken:jjwt-api:0.11.5") testRuntimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5") testRuntimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5") }
- 测试代码生成Token并构建请求:
import io.jsonwebtoken.Jwts import io.jsonwebtoken.SignatureAlgorithm import java.util.* @Test fun `update`() { val url = "http://localhost:${port}${basePath}/update" // 生成模拟JWT Token(密钥需与应用配置一致) val secretKey = "your-test-secret-key" val jwtToken = Jwts.builder() .setSubject("username") .claim("someClaim", "someClaimValue") .claim("scope", "write") // 对应SCOPE_write权限 .setIssuedAt(Date()) .setExpiration(Date(System.currentTimeMillis() + 3600000)) .signWith(SignatureAlgorithm.HS256, secretKey.toByteArray()) .compact() // 构建带Bearer Token的请求头 val headers = HttpHeaders() headers.setBearerAuth(jwtToken) val body = HttpEntity( UpdateRequest( // 请求对象参数 ), headers ) val response = restTemplate.exchange( url, HttpMethod.PUT, body, typeReference<SomeResponseType>() ) }
额外注意点
控制器代码存在拼写错误:@RequestMappting需改为@RequestMapping,避免路由配置失效。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

