微服务网关

一、概念

网关就是网络的接口,负责请求的路由、转发、身份校验。
在这里插入图片描述

二、快速入门

1.创建依赖

2.引入网关依赖

<!--网关-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>

3.编写启动类

4.配置路由规则
在这里插入图片描述

 server:
  port: 8080
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: 192.168.86.128:8848
    gateway:
      routes:
        - id: item
          uri: lb://item-service
          predicates:
            - Path=/items/**,/search/**

三、路由过滤器

这是全局过滤器,局部过滤器是配置在routes里面,即predicates下面(不加default)

      default-filters:
        - AddRequestHeader=truth,patience is key in life

在这里插入图片描述

四、网关登录校验

在这里插入图片描述
在这里插入图片描述

1.如何在网关登录校验之前做登录校验?

  • 首先自定义一个过滤器,保证这个过滤器的执行顺序在nettyRoutingFilter之前
  • 然后在他的pre逻辑里去实现jwt校验

2.网关如何将用户信息传递给微服务?

  • 网关在校验完后将用户放到请求头,然后再发请求到微服务,微服务再从请求头里取出用户

接下来需要做的事情:

  • 如何在网关里去自定义过滤器,并控制顺序?
  • 如何在网关里编写登录校验的逻辑?
  • 这样把网关里得到的用户向下游微服务传递?
  • 微服务之间怎么区传递?

1.自定义过滤器

过滤器有两种:

  • GatewayFilter:路由过滤器,作用于任意指定的路由;默认不生效,要配置到路由后生效。
  • GlobalFilter:全局过滤器,作用范围是所有路由;声明后自动生效。

示例:GlobalFilter

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = request.getHeaders();
        System.out.println("headers: " + headers);
        //放行
        return chain.filter(exchange);
    }

    //代表优先级,值越小优先级越高
    @Override
    public int getOrder() {
        return 0;
    }
}

2.实现登录校验

需求:在网关中基于过滤器实现登录校验功能。

该功能在hm-getway模块。

@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) {
        //获取Request
        ServerHttpRequest request = exchange.getRequest();
        //判断是否需要拦截器拦截
        if(isExclude(request.getPath().toString())){
            return chain.filter(exchange);
        }
        //获取token
        String token=null;
        List<String> heards = request.getHeaders().get("authorization");
        if(heards!=null && !heards.isEmpty()){
            token = heards.get(0);
        }
        //校验并解析token
        Long userId = null;
        try {
            userId = jwtTool.parseToken(token);
        } catch (Exception e) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

		System.out.println("用户id:"+userId);

       
        //放行
        return chain.filter(swe);

    }

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

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

3. 网关传递用户

首先,在getway的AuthGlobalFilter添加相关信息(即将上方System.out.println(“用户id:”+userId);改成下方代码)

//TODO 传递用户信息
        String userInfo=userId.toString();
        ServerWebExchange swe = exchange.mutate()
                .request(builder -> builder.header("user-info", userInfo))
                .build();

然后,在hm-common添加拦截器

public class UserInfoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取登录用户信息
        String header = request.getHeader("user-info");
        //判断是否获取了用户,如果有,存入ThreadLocal
        if (StrUtil.isNotBlank(header)) {
            UserContext.setUser(Long.valueOf(header));
        }
        //放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        UserContext.removeUser();
    }
}

最后,定义springmvc的配置类定义拦截器

@Configuration
// 判断DispatcherServlet类是否存在(是否是微服务,只要是微服务都有spirngmvc,有springmvc就有其核心api,即下方注解的类)
@ConditionalOnClass(DispatcherServlet.class)
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UserInfoInterceptor());
    }
}

配置完后还有问题:每个微服务启动类所在的包都不一样,导致每个微服务的包都扫不到common里的mvcconfig,使得配置类不生效。

方案:在resources包的META-INF包下定义一个文件去记录这些配置类,这样项目一启动就会找到这些配置类
在这里插入图片描述

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.hmall.common.config.MvcConfig

4.OpenFeign传递用户

在这里插入图片描述
定义oprnFeign的拦截器,保存用户到请求头
在这里插入图片描述

public class DefaultFeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

    @Bean
    public RequestInterceptor userInfoRequestInterceptor() {
        return new RequestInterceptor() {

            @Override
            public void apply(RequestTemplate requestTemplate) {
                Long userId = UserContext.getUser();
                if (userId != null) {
                    requestTemplate.header("user-info",userId.toString());
                }
            }
        };
    }

    @Bean
    public ItemClientFallbackFactory itemClientFallbackFactory() {
        return new ItemClientFallbackFactory();
    }
}

在这里插入图片描述

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐