微服务下计划一个注解标识是否须要登录

[复制链接]
发表于 2026-1-19 00:43:10 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
需求

现在我们是微服务体系,须要计划一个注解 @RequiredLogin ,当标识这个注解时表现体系须要登录才气继承操纵。
实现思绪

起首,须要明白我们要拦截的是从欣赏器过来的哀求,服务之间的相互调用是不须要拦截的(比如 Feign 调用)。下图是一些交互环境。
 


我们在网关的全局过滤器中添加一个标识 X(表现他是从欣赏器过来的),然后在每次 Feign 远程调用之前标识一下 Y(表现是内部远程调用),末了在每个服务的拦截器(这个可以抽出通用拦截器设置)中拦截哀求头中的信息举行判断即可。

代码实现

界说注解
  1. @Target({ElementType.METHOD})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface RequireLogin {
  5. }
复制代码
网关的全局过滤器
  1. /**
  2. * 定义全局过滤器,功能如下:
  3. * 1.把客户端真实IP通过请求同的方式传递给微服务
  4. * 2.在请求头中添加FEIGN_REQUEST的请求头,值为0,标记请求不是Feign调用,而是客户端调用
  5. * 3.刷新Token的有效时间
  6. */
  7. @Component
  8. public class CommonFilter implements GlobalFilter {
  9.     @Autowired
  10.     private StringRedisTemplate redisTemplate;
  11.     @Override
  12.     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  13.         /**
  14.          * pre拦截逻辑
  15.          * 在请求去到微服务之前,做了两个处理
  16.          * 1.把客户端真实IP通过请求同的方式传递给微服务
  17.          * 2.在请求头中添加FEIGN_REQUEST的请求头,值为0,标记请求不是Feign调用,而是客户端调用
  18.          */
  19.         ServerHttpRequest request = exchange.getRequest().mutate().
  20.                 header(CommonConstants.REAL_IP,exchange.getRequest().getRemoteAddress().getHostString()).
  21.                 header(CommonConstants.FEIGN_REQUEST_KEY,CommonConstants.FEIGN_REQUEST_FALSE).
  22.                 build();
  23.         return chain.filter(exchange.mutate().request(request).build()).then(Mono.fromRunnable(()->{
  24.             /**
  25.              * post拦截逻辑
  26.              * 在请求执行完微服务之后,需要刷新token在redis的时间
  27.              * 判断token不为空 && Redis还存在这个token对于的key,这时候需要延长Redis中对应key的有效时间.
  28.              */
  29.             String token,redisKey;
  30.             if(!StringUtils.isEmpty(token = exchange.getRequest().getHeaders().getFirst(CommonConstants.TOKEN_NAME))
  31.                     && redisTemplate.hasKey(redisKey = CommonRedisKey.USER_TOKEN.getRealKey(token))){
  32.                 redisTemplate.expire(redisKey, CommonRedisKey.USER_TOKEN.getExpireTime(), CommonRedisKey.USER_TOKEN.getUnit());
  33.             }
  34.         }));
  35.     }
  36. }
复制代码
Feign 远程调用的前置拦截
  1. /**
  2. * Feign调用时添加标记为此时是通过Feign进行调用(不需要登录)
  3. */
  4. public class FeignRequestInterceptor implements RequestInterceptor {
  5.     @Override
  6.     public void apply(RequestTemplate template) {
  7.         template.header(CommonConstants.FEIGN_REQUEST_KEY,CommonConstants.FEIGN_REQUEST_TRUE);
  8.     }
  9. }
复制代码
每个哀求都要走的通用登录拦截器
  1. public class RequireLoginInterceptor implements HandlerInterceptor {
  2.     private StringRedisTemplate redisTemplate;
  3.     public RequireLoginInterceptor(StringRedisTemplate redisTemplate){
  4.         this.redisTemplate = redisTemplate;
  5.     }
  6.     @Override
  7.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  8.         if(handler instanceof HandlerMethod){
  9.             HandlerMethod handlerMethod = (HandlerMethod) handler;
  10.             String feignRequest = request.getHeader(CommonConstants.FEIGN_REQUEST_KEY);
  11.             //如果是feign请求,直接放行
  12.             if(!StringUtils.isEmpty(feignRequest) && CommonConstants.FEIGN_REQUEST_TRUE.equals(feignRequest)){
  13.                 return true;
  14.             }
  15.             //如果不是Feign请求,判断是否有贴RequireLogin注解
  16.             if(handlerMethod.getMethodAnnotation(RequireLogin.class)!=null){
  17.                 response.setContentType("application/json;charset=utf-8");
  18.                 String token = request.getHeader(CommonConstants.TOKEN_NAME);
  19.                 if(StringUtils.isEmpty(token)){
  20.                     response.getWriter().write(JSON.toJSONString(Result.error(CommonCodeMsg.TOKEN_INVALID)));
  21.                     return false;
  22.                 }
  23.                 String phone = JSON.parseObject(redisTemplate.opsForValue().get(CommonRedisKey.USER_TOKEN.getRealKey(token)),String.class);
  24.                 if(phone==null){
  25.                     response.getWriter().write(JSON.toJSONString(Result.error(CommonCodeMsg.TOKEN_INVALID)));
  26.                     return false;
  27.                 }
  28.             }
  29.         }
  30.         return true;
  31.     }
  32. }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表