Feign设置Token鉴权调用接口
声明FeignClient 指定url
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/** * CREATE BY songzhongjin ON 2021.05.08 15:58 星期六 * DESC:feign方式 测试Deom */ @FeignClient (name = "testService" , url = "http://xxxxxx:8088" ) public interface FeignTest { /** * 通过feign调用接口 * @param map * @return */ @PostMapping (value = "/xxxxx/sys/login" ) String login(Map<String, Object> map); } |
调用测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/** * CREATE BY songzhongjin ON 2021.05.08 16:02 星期六 * DESC: */ @RestController public class Test { @Autowired FeignTest feignTest; @Autowired MetaDataService metaDataService; @PostMapping ( "/test" ) public void test() { HashMap<String, Object> map = new HashMap<>(); map.put( "user_id" , "xxx" ); map.put( "password" , "xxxxx" ); //调用 T 具体对象具体封装 MetaDataResponseVO<T> login = feignTest.login(map); List<T> data = login.getData(); System.out.println(login.getData()); //处理业务data } } |
返回对象可以封装demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Data public class MetaDataResponseVO<T> implements Serializable { private static final long serialVersionUID = 316492198399615153L; /** * 状态码. */ private String retcode; /** * 状态码描述. */ private String retmsg; /** * 响应包体. */ private List<T> data; } |
设置token 进行调用,Feign 的请求拦截器来统一添加请求头信息
先去implements RequestInterceptor 重写apply方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/** * feign拦截器配置,调用前先鉴权. */ @Component public class MetaDataFeignConfig implements RequestInterceptor { public FeignBasicAuthRequestInterceptor() { } /** * 给feign请求加上accessToken请求头. * * @param template */ @Override public void apply(RequestTemplate template) { //feign加请求头 自定义fangjia.auth.token" template.header( "access_token" , System.getProperty( "fangjia.auth.token" )); } } |
配置拦截器
拦截器需要在 Feign 的配置中定义,代码如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@Configuration public class FeignConfiguration { /** * 日志级别 * * @return */ @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } /** * 创建 Feign 请求拦截器, 在发送请求前设置认证的 Token, 各个微服务将 Token 设置 到环境变量中来达到通用的目的 * * @return */ @Bean public FeignBasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new FeignBasicAuthRequestInterceptor(); } } |
上面的准备好之后,我们只需要在调用业务接口之前先调用认证接口,然后将获取到的 Token 设置到环境变量中,通过 System.setProperty(“fangjia.auth.token”,token) 设置值,可以使用redis存放避免每次调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Value ( "${feign-client.meta-data.user}" ) private String userId; @Value ( "${feign-client.meta-data.password}" ) private String password; private static final String METADATA_ACCESS_TOKEN = "metaDataAccessToken" ; /** * 获取token,设置到上下文. */ public void signInMetaData() { //拿缓存 String accessToken = redisUtils.get(METADATA_ACCESS_TOKEN); log.warn( "-----------从redis拿meta的token结果--token ={}-------------" , accessToken); //System.setProperty("fangjia.metadata.token",token) 设置token值 System.setProperty( "feign.metadata.token" , accessToken); log.warn( "--------------设置metaData接口鉴权结束-----------------" ); } |
token设置完成,我们需要在我们其他的feign文件中配置这个token,
注意配置对应的拦截器configuration ,MetaDataFeignConfig.class这个类就是我们设置头信息的
1
|
@FeignClient (name = “metaDataClient”, url = “${feign-client.meta-data.url}”, configuration = MetaDataFeignConfig. class ) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package com.infinitus.dmm.openapi; /** * 无限极元数据接口. * * @author 林志鹏 * @date 2021/5/7 */ @FeignClient (name = "metaDataClient" , url = "${feign-client.meta-data.url}" , configuration = MetaDataFeignConfig. class ) public interface MetaDataClient { /** * 拉取物理系统列表. */ @RequestMapping (value = "/sc/mtdsystemlist" , method = RequestMethod.GET) MetaDataResponseVO<MetaDataSystem> pullPhysicalSystemList(); |
我们在调用该业务接口时候,需要先去调用设置头信息feign,在调用业务feign。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/** * 拉取物理系统列表. * * @return */ public List<MetaDataSystem> pullPhysicalSystem() { //鉴权feign signInMetaData(); //业务feign MetaDataResponseVO<MetaDataSystem> responseVO = metaDataClient.pullPhysicalSystemList(); if (Objects.nonNull(responseVO)) { List<MetaDataSystem> data = responseVO.getData(); if (Objects.nonNull(data) && !data.isEmpty()) { return data; } } return new ArrayList<>(); } |
补充
经过测试 鉴权接口调用成功,但是业务接口返回竟然超过10s feign默认的返回1秒就会触发熔断机制,所以我们需要设置feign的超时时间,可以指定FeignClient 名name 很人性化。
1
|
@FeignClient (name = “metaDataClient”, url = “${feign-client.meta-data.url}”) |
1
2
3
4
5
6
7
8
9
|
#给metaDataClient服务设置超时时间 这里metaDataClient是我自己,全局的话metaDataClient替换default feign: client: config: metaDataClient: connect-timeout: 50000 read-timeout: 50000 hystrix: enabled: false |
Feign调用进行Token鉴权
项目场景
这边使用 两个springboot应用,中间通过feign来进行远程调用(是的没错,架构就是这么奇葩)。然后在调用feign的时候,希望可以进行token鉴权。
解决办法
请求进来时,通过拦截器,校验header的token,然后在业务中调用feignClient时,通过新加一个feign拦截器,拦截feign请求,把当前的header中的token添加到feign的请求头中去。实现token在链路中的传递。
具体实现
新增 feign 拦截器配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/** * Feign请求拦截器配置. * * @author linzp * @version 1.0.0 * @date 2021/4/16 21:19 */ @Configuration public class FeignInterceptorConfig implements RequestInterceptor { public FeignInterceptorConfig() {} @Override public void apply(RequestTemplate template) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //设置token到请求头 template.header(ConstantCommon.HEADER_TOKEN_KEY, request.getHeader(ConstantCommon.HEADER_TOKEN_KEY)); } } |
然后在feignClient接口中,添加 == configuration = FeignInterceptorConfig.class==
注意有Bug!!!
注意!!!,这里会有个异常,获取到的request会是null。原因是hytrix隔离策略是thread,无法读到 threadLocal变量。
解决办法!!更改策略
在配置文件中新增如下配置,即可解决!
1
2
3
4
5
6
7
|
# 更换hystrix策略,解决无法传递threadLocal变量问题 hystrix: command: default: execution: isolation: strategy: SEMAPHORE |
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/weixin_42771651/article/details/116664108