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

Spring Boot集成Keycloak:Refresh Token刷新令牌实现求助

解决Keycloak刷新令牌问题

核心修改方案

在AuthenticationServiceImpl的refreshLogin方法中,需要通过传入的refreshToken初始化Keycloak实例,并调用专属的刷新令牌方法,而非重复使用用于用户名密码登录的grantToken()。

修改后的完整代码

@Service
class AuthenticationServiceImpl: AuthenticationService {
    @Value("\${keycloak.address}")
    private lateinit var keycloakAddress: String
    // 若Keycloak客户端为「保密客户端(Confidential)」,需添加客户端密钥配置
    // @Value("\${keycloak.client-secret}")
    // private lateinit var clientSecret: String

    override fun login(loginDTO: LoginDTO): JwtDTO? {
        val keycloak = KeycloakBuilder.builder()
            .serverUrl("http://$keycloakAddress")
            .realm("wa2-products")
            .clientId("wa2-products-client")
            // 保密客户端需取消此行注释
            // .clientSecret(clientSecret)
            .username(loginDTO.email)
            .password(loginDTO.password)
            .build()

        return try {
            val tokenSet = keycloak.tokenManager().grantToken()
            JwtDTO(tokenSet.token, tokenSet.refreshToken)
        } catch (e: NotAuthorizedException) {
            null
        }
    }

    override fun refreshLogin(refreshToken: String): JwtDTO? {
        val keycloak = KeycloakBuilder.builder()
            .serverUrl("http://$keycloakAddress")
            .realm("wa2-products")
            .clientId("wa2-products-client")
            // 保密客户端需取消此行注释
            // .clientSecret(clientSecret)
            .refreshToken(refreshToken) // 传入客户端提供的刷新令牌
            .build()

        return try {
            val tokenSet = keycloak.tokenManager().refreshToken() // 调用刷新令牌专用方法
            JwtDTO(tokenSet.token, tokenSet.refreshToken)
        } catch (e: NotAuthorizedException) {
            null
        }
    }
}

关键说明

  1. 传入刷新令牌:通过KeycloakBuilder的.refreshToken(refreshToken)方法,告知Keycloak客户端基于传入的刷新令牌发起新的令牌请求。
  2. 调用正确方法:使用tokenManager().refreshToken()而非grantToken(),该方法会向Keycloak令牌端点发送refresh_token类型的请求,返回新的access token(通常会同时返回新的refresh token,具体取决于Realm的令牌配置)。
  3. 客户端类型适配:若你的Keycloak客户端是「保密客户端」,必须添加.clientSecret(clientSecret)配置,否则Keycloak会拒绝刷新请求;公开客户端则无需此配置。

额外优化建议

不要将refreshToken放在URL路径中(@PathVariable refreshToken),避免令牌被日志记录或泄露,建议改为放在请求体中:

// 修改AuthenticationController的刷新端点
@PostMapping("/API/refreshLogin")
fun refreshLogin(@RequestBody refreshTokenRequest: RefreshTokenRequest): JwtDTO {
    return authenticationService.refreshLogin(refreshTokenRequest.refreshToken) ?: throw GenericException()
}

// 新增请求DTO
data class RefreshTokenRequest(val refreshToken: String)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 03:08:11