马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
需求
现在我们是微服务体系,须要计划一个注解 @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 {
- @Autowired
- private StringRedisTemplate redisTemplate;
- @Override
- public 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 {
- @Override
- public 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;
- }
- @Override
- public 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;
- }
- }
复制代码 |