当前位置: 首页 > news >正文

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

需求

现在我们是微服务系统,需要设计一个注解 @RequiredLogin ,当标识这个注解时表示系统需要登录才能继续操作。

实现思路

首先,需要明确我们要拦截的是从浏览器过来的请求,服务之间的互相调用是不需要拦截的(比如 Feign 调用)。下图是一些交互情况。

 

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

代码实现

定义注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequireLogin {
}

网关的全局过滤器

/*** 定义全局过滤器,功能如下:* 1.把客户端真实IP通过请求同的方式传递给微服务* 2.在请求头中添加FEIGN_REQUEST的请求头,值为0,标记请求不是Feign调用,而是客户端调用* 3.刷新Token的有效时间*/
@Component
public class CommonFilter implements GlobalFilter {@Autowiredprivate StringRedisTemplate redisTemplate;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {/*** pre拦截逻辑* 在请求去到微服务之前,做了两个处理* 1.把客户端真实IP通过请求同的方式传递给微服务* 2.在请求头中添加FEIGN_REQUEST的请求头,值为0,标记请求不是Feign调用,而是客户端调用*/ServerHttpRequest request = exchange.getRequest().mutate().header(CommonConstants.REAL_IP,exchange.getRequest().getRemoteAddress().getHostString()).header(CommonConstants.FEIGN_REQUEST_KEY,CommonConstants.FEIGN_REQUEST_FALSE).build();return chain.filter(exchange.mutate().request(request).build()).then(Mono.fromRunnable(()->{/*** post拦截逻辑* 在请求执行完微服务之后,需要刷新token在redis的时间* 判断token不为空 && Redis还存在这个token对于的key,这时候需要延长Redis中对应key的有效时间.*/String token,redisKey;if(!StringUtils.isEmpty(token = exchange.getRequest().getHeaders().getFirst(CommonConstants.TOKEN_NAME))&& redisTemplate.hasKey(redisKey = CommonRedisKey.USER_TOKEN.getRealKey(token))){redisTemplate.expire(redisKey, CommonRedisKey.USER_TOKEN.getExpireTime(), CommonRedisKey.USER_TOKEN.getUnit());}}));}
}

Feign 远程调用的前置拦截

/*** Feign调用时添加标记为此时是通过Feign进行调用(不需要登录)*/
public class FeignRequestInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {template.header(CommonConstants.FEIGN_REQUEST_KEY,CommonConstants.FEIGN_REQUEST_TRUE);}
}

每个请求都要走的通用登录拦截器

public class RequireLoginInterceptor implements HandlerInterceptor {private StringRedisTemplate redisTemplate;public RequireLoginInterceptor(StringRedisTemplate redisTemplate){this.redisTemplate = redisTemplate;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if(handler instanceof HandlerMethod){HandlerMethod handlerMethod = (HandlerMethod) handler;String feignRequest = request.getHeader(CommonConstants.FEIGN_REQUEST_KEY);//如果是feign请求,直接放行if(!StringUtils.isEmpty(feignRequest) && CommonConstants.FEIGN_REQUEST_TRUE.equals(feignRequest)){return true;}//如果不是Feign请求,判断是否有贴RequireLogin注解if(handlerMethod.getMethodAnnotation(RequireLogin.class)!=null){response.setContentType("application/json;charset=utf-8");String token = request.getHeader(CommonConstants.TOKEN_NAME);if(StringUtils.isEmpty(token)){response.getWriter().write(JSON.toJSONString(Result.error(CommonCodeMsg.TOKEN_INVALID)));return false;}String phone = JSON.parseObject(redisTemplate.opsForValue().get(CommonRedisKey.USER_TOKEN.getRealKey(token)),String.class);if(phone==null){response.getWriter().write(JSON.toJSONString(Result.error(CommonCodeMsg.TOKEN_INVALID)));return false;}}}return true;}
}


http://www.mrgr.cn/news/28820.html

相关文章:

  • ccfcsp-202203(1、2)
  • LaTex2024 下载安装运行HelloWorld—全流程笔记
  • 动手学深度学习(四)卷积神经网络-下
  • 数据结构易错整理1
  • C++基础知识7 list
  • 变压器漏感对整流电路的影响
  • C++学习笔记(28)
  • 进程间关系与进程守护
  • ZooKeeper远程连接超时排查与解决
  • 如何用安卓玩Java版Minecraft,安卓手机安装我的世界Java版游戏的教程
  • 过拟合与欠拟合、批量标准化
  • docker- No space left on device
  • 开源模型应用落地-qwen模型小试-调用Qwen2-VL-7B-Instruct-更清晰地看世界(一)
  • 紧急预警!台风贝碧嘉正面袭击上海浦东,风雨交加影响全城
  • 自然语言处理实战项目
  • 文件标识符fd
  • 【看这里】记录一下,如何在springboot中使用EasyExcel并行导出多个Excel文件并压缩zip后下载
  • Java 性能调优:优化 GC 线程设置
  • 【C++前后缀分解】1653. 使字符串平衡的最少删除次数|1793
  • DFS:二叉树中的深搜