springcloud/springmvc协调作用传递验证信息

微服务架构的拆分,各模块之间使用feign组件来进行相互http转发通信。

前端与后端之间使用springcloud的网关来进行协调。

现在问题出现,用户的信息如何进行传递?

前端请求携带请求头,请求头中的authorization为携带的对应token,这个token如何转发给各个微服务模块?

具体流程:前端发送请求->网关进行解析->从springcloud拦截器的exchange.header中解析出token->将token写入到新的exchange.header中,并且命名为info,这个exchange会被向后传递(因为本身springcloud就有多个拦截器,该拦截器处理完之后会传递给下一个拦截器 )->根据网关解析的端口号,发送request到对应端口的微服务中->微服务的拦截器对request进行拦截(实际上是一个共有模块,各个微服务依赖于这个模块,所以其网络请求会被该模块拦截)->读取传递过来请求头中的info信息,存入threadLocal中。

1.由于所有前端请求都会到达springcloud的拦截器,并且拦截器有多个,只需在拦截器中将需要传递的"info"存进网络请求中,对应的拦截器定义如下:

javascript 复制代码
package com.hxy.hmgateway.filter;

import com.hxy.hmgateway.config.AuthProperties;
import com.hxy.hmgateway.utils.JwtTool;
import lombok.RequiredArgsConstructor;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Component
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    private final AuthProperties authProperties;
    private final JwtTool jwtTool;
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        //放行排除路径
        String path = request.getPath().toString();
        if(isExclude(path,authProperties.getExcludePaths())){
            return chain.filter(exchange);
        }
        //1.获取token
        HttpHeaders headers = request.getHeaders();
        List<String> tokenList = headers.get("authorization");
        //2.判别token是否为空
        String token = null;
        if (tokenList!=null && !tokenList.isEmpty()){
            token = tokenList.get(0);
        }
        //3.获取userId
        Long userId = null;
        //4.判别token是否正确
        try {
            userId = jwtTool.parseToken(token);
        } catch (Exception e) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //TODO userId的转发
        System.out.println("userId:"+userId);
        String userInfo = String.valueOf(userId);
        ServerWebExchange swe = exchange.mutate().request(builder ->
                builder.header("info", userInfo)).build();
        //5.放行
        return chain.filter(swe);
    }

    private boolean isExclude(String path, List<String> excludePaths) {
        for (String pathPattern : excludePaths) {
            if(antPathMatcher.match(pathPattern, path)) return true;
        }
        return false;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

注意这里的exchange.mutate指令用于将info存储在网络请求中。

2.该拦截器经过springcloud网关转发后,首先到达所有微服务公共依赖的模块,这个模块会使用springmvc拦截器,用于拦截,info,并将其存入threadlocal中。代码如下;

java 复制代码
package com.hmall.common.intercepter;

import com.hmall.common.utils.UserContext;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class UserInfoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String info = request.getHeader("info");
        if (info == null) return true;
        Long userId = Long.valueOf(info);
        UserContext.setUser(userId);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        UserContext.removeUser();
    }
}
java 复制代码
package com.hmall.common.config;

import com.hmall.common.intercepter.UserInfoInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ConditionalOnClass(DispatcherServlet.class)
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UserInfoInterceptor());
    }
}

为了使得其余微服务能够扫描到该共有模块的包,需要将拦截器对应的包添加在如下文件中:

对应的spring.factories文件如下:

bash 复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.hmall.common.config.MyBatisConfig,\
  com.hmall.common.config.MvcConfig,\
  com.hmall.common.config.JsonConfig

最后需要注意,在mvc配置文件中,添加了一个注解

复制代码
ConditionalOnClass,用于标记仅对使用了该类的模块生效
相关推荐
崎岖Qiu3 分钟前
【Spring篇08】:理解自动装配,从spring.factories到.imports剖析
java·spring boot·后端·spring·面试·java-ee
香饽饽~、1 小时前
【第十一篇】SpringBoot缓存技术
java·开发语言·spring boot·后端·缓存·intellij-idea
述雾学java2 小时前
Spring Cloud 服务追踪实战:使用 Zipkin 构建分布式链路追踪
分布式·spring·spring cloud·zipkin
程序员爱钓鱼2 小时前
Go语言实战指南 —— Go中的反射机制:reflect 包使用
后端·google·go
ℳ₯㎕ddzོꦿ࿐2 小时前
Spring Boot 集成 MinIO 实现分布式文件存储与管理
spring boot·分布式·后端
MonkeyKing_sunyuhua6 小时前
Ehcache、Caffeine、Spring Cache、Redis、J2Cache、Memcached 和 Guava Cache 的主要区别
redis·spring·memcached
ai小鬼头7 小时前
百度秒搭发布:无代码编程如何让普通人轻松打造AI应用?
前端·后端·github
考虑考虑7 小时前
@FilterRegistration和@ServletRegistration注解
spring boot·后端·spring
一只叫煤球的猫7 小时前
🔥 同事混用@Transactional和TransactionTemplate被我怼了,三种事务管理到底怎么选?
java·spring boot·后端
你的人类朋友9 天前
(●'◡'●)从Dockerfile快速入门Docker Compose
后端