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 } } }
关键说明
- 传入刷新令牌:通过
KeycloakBuilder的.refreshToken(refreshToken)方法,告知Keycloak客户端基于传入的刷新令牌发起新的令牌请求。 - 调用正确方法:使用
tokenManager().refreshToken()而非grantToken(),该方法会向Keycloak令牌端点发送refresh_token类型的请求,返回新的access token(通常会同时返回新的refresh token,具体取决于Realm的令牌配置)。 - 客户端类型适配:若你的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
相关产品推荐
相关产品推荐

