最近有个需求,调用某服务器API时,先从服务器取得token,token取得失败再使用账密重试,这里还要求使用拦截器处理.
那么问题来了,对RestTemplate拦截的话,会导致我从服务器取得token也被拦截,如何能跳过取token的请求呢?
有一个方法就是直接在拦截器中根据获取token的请求路径来判断,但当有多个不同的服务器token要跳过的话,代码很臃肿,不易于理解.
解决办法:使用构造器注入
在需要调用API的地方注入带有拦截器的RestTemplate();拦截器中使用 new RestTemplate()中来取得token.
WebSecurityConfig.java配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
...
@Bean
public ServiceAProxy serviceAProxy() throws Exception {
// A服务类注入带有拦截器A的RestTemplate()
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Collections.singletonList(myInterceptorA()));
// 构造器注入
return new ServiceAProxy(restTemplate);
}
@Bean
public MyInterceptorAmyInterceptorA() throws Exception {
// 拦截器A中直接使用new RestTemplate()获取token
return new MyInterceptorAmyInterceptorA();
}
@Bean
public ServiceBProxy serviceBProxy() throws Exception {
// B服务类注入带有拦截器B的RestTemplate()
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Collections.singletonList(myInterceptorB()));
// 构造器注入
return new ServiceBProxy(restTemplate);
}
@Bean
public MyInterceptorAmyInterceptorB() throws Exception {
// 拦截器B中直接使用new RestTemplate()获取token
return new MyInterceptorAmyInterceptorB();
}
}
ServiceAProxy
public class ServiceAProxy {
/**
* RestTemplate
*/
private RestTemplate restTemplate;
// 构造器注入
@Autowired
public ServiceAProxy(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
...
}
MyInterceptorA
public class MyInterceptorA implements ClientHttpRequestInterceptor {
/**
* RestTemplate
*/
private RestTemplate restTemplate = new RestTemplate();
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
// Head
HttpHeaders requestHeaders = request.getHeaders();
var accesstoken = tokenService.getToekn(ACCESSTOKEN_ID);
requestHeaders.set("content-type", "application/json");
requestHeaders.add(apiKeys, apiValue);
requestHeaders.add("Authorization", "Bearer " + accesstoken);
var response = execution.execute(request, body);
// 不是认证错误则退出
if (HttpStatus.UNAUTHORIZED != response.getStatusCode()) {
return response;
}
// 第一次认证错误时,使用刷新Token重试
var accessToken = getRefreshToekn();
if (!Strings.isEmpty(accessToken)) {
requestHeaders.set("Authorization", "Bearer " + accessToken);
response = execution.execute(request, body);
// 不是认证错误则退出
if (HttpStatus.UNAUTHORIZED != response.getStatusCode()) {
return response;
}
}
// 第二次认证错误使用账户密码重新取得token
accessToken = getToeknByUserPassWord();
requestHeaders.set("Authorization", "Bearer " + accessToken);
response = execution.execute(request, body);
return response;
}
}