如何在Quarkus框架中实现JWT refresh token功能
Quarkus 框架JWT Refresh Token 实现方案
前置准备
你已经完成Quarkus JWT基础安全配置的前提下,可按照以下步骤实现刷新令牌功能:
1. 引入所需依赖
在项目pom.xml(Maven)或build.gradle(Gradle)中添加核心依赖:
- 基础JWT能力:
io.quarkus:quarkus-smallrye-jwt - 存储依赖(二选一即可):
- Redis存储(推荐生产使用):
io.quarkus:quarkus-redis-client - 数据库存储:
io.quarkus:quarkus-hibernate-orm-panache+ 对应数据库驱动
- Redis存储(推荐生产使用):
2. 核心规则定义
- AccessToken:有效期10~15分钟,携带用户身份、权限信息,用于接口鉴权
- RefreshToken:有效期7~30天,仅关联用户ID,不携带权限信息,仅用于刷新AccessToken,必须在服务端持久化存储校验
3. 登录接口实现(返回双Token)
校验用户账号密码合法后,同时生成AccessToken和RefreshToken返回给客户端:
@Path("/auth") public class AuthController { @Inject UserService userService; @Inject RefreshTokenService refreshTokenService; @POST @Path("/login") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response login(LoginRequest request) { // 校验账号密码合法性 if (!userService.checkCredentials(request.getUsername(), request.getPassword())) { return Response.status(Response.Status.UNAUTHORIZED).build(); } // 生成短期AccessToken String accessToken = Jwt.issuer("your-app-issuer") .subject(request.getUsername()) .groups(userService.getUserRoles(request.getUsername())) .expiresIn(15 * 60) .sign(); // 生成RefreshToken String refreshToken = UUID.randomUUID().toString(); // 持久化存储RefreshToken,设置对应过期时间 refreshTokenService.save(refreshToken, request.getUsername(), 7 * 24 * 60 * 60); return Response.ok(Map.of( "access_token", accessToken, "refresh_token", refreshToken, "expires_in", 15 * 60 )).build(); } }
4. 刷新令牌接口实现
客户端AccessToken过期后,携带RefreshToken调用该接口获取新的AccessToken:
@POST @Path("/refresh") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response refreshToken(RefreshTokenRequest request) { String refreshToken = request.getRefreshToken(); // 校验RefreshToken是否存在、未过期 Optional<String> usernameOpt = refreshTokenService.validateAndGetUsername(refreshToken); if (usernameOpt.isEmpty()) { return Response.status(Response.Status.UNAUTHORIZED).entity("无效刷新令牌").build(); } String username = usernameOpt.get(); // 生成新的AccessToken String newAccessToken = Jwt.issuer("your-app-issuer") .subject(username) .groups(userService.getUserRoles(username)) .expiresIn(15 * 60) .sign(); // 可选:滚动刷新策略,生成新的RefreshToken,作废旧的,降低盗用风险 String newRefreshToken = UUID.randomUUID().toString(); refreshTokenService.delete(refreshToken); refreshTokenService.save(newRefreshToken, username, 7 * 24 * 60 * 60); return Response.ok(Map.of( "access_token", newAccessToken, "refresh_token", newRefreshToken, "expires_in", 15 * 60 )).build(); }
5. 登出接口实现
用户登出时删除服务端存储的RefreshToken,避免被恶意使用:
@POST @Path("/logout") public Response logout(RefreshTokenRequest request) { refreshTokenService.delete(request.getRefreshToken()); return Response.ok().build(); }
注意事项
- JWT是明文编码格式,AccessToken中不要存储敏感信息
- 所有RefreshToken的有效性校验必须走服务端存储,不要信任客户端传递的额外信息
- 生产环境建议开启RefreshToken的IP、设备指纹绑定校验,进一步提升安全性
- Redis存储RefreshToken时可直接使用过期键功能,自动清理过期数据,无需额外定时任务
内容的提问来源于stack exchange,提问作者Henry
相关产品推荐
相关产品推荐

