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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 01:47:40