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

如何在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 + 对应数据库驱动

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 18:33:03