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

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并添加到请求头:

  1. 引入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")
}
  1. 测试代码生成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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 08:42:48