Micronaut Security:资源客户端返回401时强制获取新AccessToken方案
解决Micronaut Client-Credentials流中401时刷新Token的问题
针对Micronaut 3.9.3版本,要实现资源服务器返回401时自动获取新的access token并重试请求,核心思路是拦截401响应、清除当前token缓存、触发新token获取并重试请求,具体实现如下:
核心原理
Micronaut的AbstractClientCredentialsClient会将获取到的token缓存到ClientCredentialsTokenCache中,只有当token过期或缓存为空时才会向认证服务器请求新token。因此,当收到401(token被撤销等场景)时,只需清除该缓存,就能触发新一轮的token获取流程。
实现步骤
1. 自定义客户端过滤器拦截401响应
创建一个HttpClientFilter,用于监听resourceClient的响应,当捕获到401状态码时,清除token缓存并重试请求:
import io.micronaut.context.annotation.Requires; import io.micronaut.http.HttpRequest; import io.micronaut.http.HttpResponse; import io.micronaut.http.MutableHttpRequest; import io.micronaut.http.annotation.Filter; import io.micronaut.http.client.ClientCredentialsTokenCache; import io.micronaut.http.filter.ClientFilterChain; import io.micronaut.http.filter.HttpClientFilter; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import javax.inject.Named; import java.util.concurrent.atomic.AtomicInteger; @Filter("/**") // 可替换为resourceClient的具体路径,缩小拦截范围 @Requires(beans = ClientCredentialsTokenCache.class) public class TokenRefreshFilter implements HttpClientFilter { private final ClientCredentialsTokenCache tokenCache; private static final int MAX_RETRY_TIMES = 1; // 限制重试次数,避免无限循环 // 注入默认的oauth2 token缓存,若自定义了client名称,需修改@Named的值 public TokenRefreshFilter(@Named("oauth2") ClientCredentialsTokenCache tokenCache) { this.tokenCache = tokenCache; } @Override public Publisher<? extends HttpResponse<?>> doFilter(HttpRequest<?> request, ClientFilterChain chain) { AtomicInteger retryCounter = new AtomicInteger(0); return Mono.defer(() -> chain.proceed(request)) .flatMap(response -> { if (response.status().getCode() == 401 && retryCounter.getAndIncrement() < MAX_RETRY_TIMES) { // 清除缓存的token,触发新token获取 tokenCache.invalidate(); // 克隆请求并移除旧Authorization头,避免携带无效token MutableHttpRequest<?> retryRequest = request.mutate().removeHeader("Authorization"); // 重试请求 return Mono.from(chain.proceed(retryRequest)); } return Mono.just(response); }); } }
2. 配置resourceClient启用过滤器
在application.yml中指定resourceClient使用上述过滤器:
micronaut: http: client: services: resourceClient: # 你的resourceClient名称 url: "https://your-resource-server-domain" filters: - TokenRefreshFilter # 绑定自定义过滤器
3. 验证效果
手动撤销当前有效token后,调用resourceClient:
- 首次请求会返回401
- 过滤器捕获到401后清除token缓存,并重发请求
- 新请求会触发
AbstractClientCredentialsClient向认证服务器获取新token - 携带新token的请求将成功访问资源服务器
注意事项
- 重试次数限制:必须设置最大重试次数,防止认证服务器持续返回无效token导致无限循环
- 缓存名称匹配:如果你的client-credentials客户端是自定义名称(而非默认的
oauth2),需修改@Named注解的值,匹配配置中的客户端名称 - 路径范围控制:
@Filter的路径可设置为resourceClient的具体接口前缀(如/api/**),避免拦截无关请求
内容的提问来源于stack exchange,提问作者priya sekar
相关产品推荐
相关产品推荐

