Rest Assured中Refresh Token并发旧令牌问题及请求实现咨询
解决Rest Assured并发场景下令牌过期及Refresh Token使用问题
一、并发场景下令牌一致性问题的解决方法
1. 加锁控制令牌生命周期
把令牌的获取、有效期检查、刷新逻辑封装到一个加锁的方法里,确保同一时间只有一个线程能执行令牌更新操作,从根源避免多个线程同时使用旧令牌或重复刷新的问题。示例代码:
private static String currentAccessToken; private static long tokenExpiryTimestamp; private static final Object tokenLock = new Object(); public String getValidAccessToken() { synchronized (tokenLock) { long now = System.currentTimeMillis(); // 提前30秒触发刷新,避免令牌刚好在请求发送时过期 if (currentAccessToken == null || now >= tokenExpiryTimestamp - 30000) { // 调用刷新接口获取新令牌 Response refreshResponse = RestAssured.given() .contentType(ContentType.JSON) .body("{\"refreshToken\": \"" + getStoredRefreshToken() + "\"}") .post("/api/token/refresh"); currentAccessToken = refreshResponse.jsonPath().getString("accessToken"); // 计算新令牌的过期时间(假设接口不返回过期时间,用固定15分钟) tokenExpiryTimestamp = now + 15 * 60 * 1000; } return currentAccessToken; } }
2. 集成Rest Assured全局过滤器
自定义一个请求过滤器,在每个请求发送前自动检查令牌有效性,过期则刷新并注入新令牌。过滤器内部同样要保证线程安全:
public class TokenAuthFilter implements Filter { private String currentToken; private long expiryTime; private final Object lock = new Object(); @Override public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec, FilterContext ctx) { synchronized (lock) { if (currentToken == null || System.currentTimeMillis() >= expiryTime - 30000) { // 执行令牌刷新 Response refreshResp = RestAssured.given() .body(Map.of("refreshToken", getStoredRefreshToken())) .post("/api/auth/refresh"); currentToken = refreshResp.jsonPath().getString("accessToken"); expiryTime = System.currentTimeMillis() + 15 * 60 * 1000; } } // 注入令牌到请求头 requestSpec.header("Authorization", "Bearer " + currentToken); return ctx.next(requestSpec, responseSpec); } }
注册过滤器到Rest Assured,之后所有请求都会自动处理令牌:
RestAssured.filters(new TokenAuthFilter());
3. 避免ThreadLocal滥用(特殊场景)
如果测试场景要求每个线程使用独立的身份令牌,可以用ThreadLocal存储,但要注意线程池复用的情况,任务结束后必须清理ThreadLocal,防止内存泄漏。这种方式会增加令牌刷新次数,仅适合多身份并行测试的场景。
二、使用Refresh Token发送请求的实现
Refresh Token的请求逻辑通常是调用专门的刷新接口,携带有效的Refresh Token,获取新的Access Token(部分系统会同时返回新的Refresh Token)。
基础实现示例
// 封装Refresh Token请求方法 public String refreshAccessToken(String refreshToken) { Response response = RestAssured.given() .contentType(ContentType.JSON) .body(Map.of("refreshToken", refreshToken)) .post("/api/auth/refresh"); // 断言请求成功,避免无效令牌继续使用 response.then().statusCode(200); // 提取并更新存储的Refresh Token(如果接口返回新的) String newRefreshToken = response.jsonPath().getString("refreshToken"); updateStoredRefreshToken(newRefreshToken); return response.jsonPath().getString("accessToken"); }
关键注意事项
- 确保Refresh Token的有效期长于Access Token,且妥善存储(比如静态变量、加密配置文件),避免泄露。
- 如果Refresh Token也过期,需要触发完整登录流程重新获取令牌对。
- 刷新操作必须加锁,防止多个线程同时使用同一个Refresh Token刷新导致旧Token被服务器失效,引发后续请求失败。
内容的提问来源于stack exchange,提问作者Carolina
相关产品推荐
相关产品推荐

