springboot中使用redis存token,考虑过期情况

1 篇文章 0 订阅

笔者场景
跨系统调用接口(A系统调用B),B系统的token有效时间7天,调用接口响应较慢(1s)。
分析
A系统的调用会引发两个操作:
  1. 需要携带用户信息登录B系统(因为B系统有身份鉴权,否则可以忽略)
  2. 调用B系统接口/test
其中,A系统的获得B系统返回结果的耗时影响较大。–> 想要缩短响应时间,使用redis存储。( 200ms+ )

原理说明:

  1. 使用拦截器对该接口进行拦截:实现RequestInterceptor并重写apply(RequestTemplate requestTemplate)方法
  2. 如果接口为/test,则继续下一步操作
  3. 用户从redis获取存储的token:redis.get(key)
  4. 如果token不为空,那么携带这个token去调用B接口/test;否则,需要重新登录,并将token存入redis,然后携带这个token去调用B接口
  5. 根据B接口/test的响应结果进行分析
    如果响应代码为401,说明token已过期或失效,从redis删除token,并重新调用B系统的/test接口(此时会重新执行步骤1);否则B接口/test返回成功

代码说明:

请求拦截类

@Slf4j
@Configuration
/* 1. 使用拦截器对该接口进行拦截:实现RequestInterceptor并重写apply(RequestTemplate requestTemplate)方法 */
public class FeignRequestIntercepter implements RequestInterceptor{
    @Autowired
    private TestService testService;
    @Autowired
    private RedisService redisService;
	@Override
	public void apply(RequestTemplate requestTemplate) {
		// 添加Bearer头
	    HttpServletRequest request = RequestContextHolder.getRequestAttributes() != null ? ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest() : null;
		if (request != null) {
	    	if (!requestTemplate.url().equals("/test")) {
		        requestTemplate.header("Authorization", request.getHeader(HttpHeaders.AUTHORIZATION));
	        } else {
	        	/*   2. 如果接口为/test,则继续下一步操作
	        	接口/test需要登录B系统,此处接的是B系统的token  */
	            String userEmail = ApiAspect.getCurrentUser();
	            /*  3. 用户从redis获取存储的token:redis.get(key) */
	            String testAccessTokenCache = redisService.get(REDIS_KEY_PREFIX_TEST + userEmail);
	            /* 4. 如果token不为空,那么携带这个token去调用B接口/test;否则,需要重新登录,并将token存入redis,然后携带这个token去调用B接口 */
	            if(StringUtils.isNotBlank(testAccessTokenCache)){
	            	requestTemplate.header("Authorization", "Bearer " + testAccessTokenCache);
	            }else{
	                String testToken = testService.getAccessToken();
	                redisService.setEx(REDIS_KEY_PREFIX_TEST + userEmail, testToken, 6, TimeUnit.DAYS);
	                requestTemplate.header("Authorization", "Bearer " + testService.getAccessToken());
	            }
	        }
	    }
	}
}

实现类

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class TestServiceImpl implements TestService {
	@Override
	public JSONObject getTestData(Long testId, String userEmail) {
        Response response = null;
        try {
            response = testFeignClient.test(testId);
            /*  5. 根据B接口/test的响应结果进行分析 
            如果响应代码为401,说明token已过期或失效,从redis删除token,并重新调用B系统的/test接口(此时会重新执行步骤1);否则B接口/test返回成功 */
            if(response.getCode().equals(CODE_ERROR_AUTH)){
                redisService.delete(REDIS_KEY_PREFIX_TSET + userEmail);
                response = testFeignClient.test(TestId);
            }
            log.info("test返回信息 {}",response);
        } catch (Exception e){
            log.error("数据返回失败error {}", e);
        }
        JSONObject data = new JSONObject();
        if(response != null) {
                if(response.getData() instanceof JSONObject) {
                    data = (JSONObject) response.getData();
                }else {
                    LinkedHashMap dataMap = (LinkedHashMap) response.getData();
                    data = JSONObject.parseObject(JSONObject.toJSONString(dataMap));
                }
        }
        return data;
    }

如果不知道testFeignClient.test(testId)中feign的配置,请跳转另一篇博文:feign配置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值