客户端与微服务之间的桥梁---网关

当我们创建好了N多个微服务或者微服务的实例之后,每个服务暴露出不同的端口地址,一般对于客户端请求,只需要请求一个端口,要隔离客户端和微服务的直接关系,保证微服务的安全性和灵活性,避免敏感信息的泄露。这时就需要网关。

网关

例如,我们在外人和村庄之间建立了一座桥梁,在桥上有一个管理员(守卫),他负责检查每个想要过桥的人。如果检查合格,他会允许通过,并告诉你要找的人的住处;如果不合格,则不允许通过。

网关充当了统一的接入点(桥梁),客户端仅需通过网关的固定端口或地址进行访问,无需了解各个微服务的具体端口和地址。网关内部根据配置的服务路由规则进行操作,一旦请求符合这些规则,网关便会从Nacos注册中心获取相应的服务地址,并将客户端的请求路由至指定的微服务。其他功能如身份校验,限流,路由转发,请求过滤等。

配置网关

将网关作为一个独立的模块,服务部署。配置启动类,引入依赖,配置路由规则即可。

到此启动网关后, 通过8080及具体的路径就可以访问到任何一个微服务了,具体是哪个是由负载均衡决定好了。但是,目前是不安全的,因为没有做身份校验。我们希望的是请求必须经过网关处理。

配置网关内部过滤拦截器

可以在网关内部声明一个全局过滤器专门处理登录校验,这个自定义过滤器要实现GlobalFilter接口,并实现其方法。过滤器有很多个,是依次链式调用的,直到最后一个。

全局过滤器链的最后一个执行的过滤器, 通常是 NettyWriteResponseFilter。它执行完了,这个过滤过程也就结束了,这个过滤器的作用是负责将响应数据写回给客户端,它是默认过滤器链中最末端的一个过滤器。对于前置过滤器,会在请求到达微服务目标之前执行,可以实现Ordered接口给过滤器设置优先级,数字越小,优先级越高,越先执行。

大致步骤:

1,需要判断当前路径是否需要拦截,不需要就放行。
java 复制代码
@Component
@RequiredArgsConstructor
public class MyAuthGlobalFilter implements GlobalFilter, Ordered {
    private final AuthProperties authProperties;
    private final static AntPathMatcher pathMatcher = new AntPathMatcher();
    

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
     
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        List<String> excludePaths = authProperties.getExcludePaths();

        // 判断当前路径是否需要拦截校验,不需要就放行
        if (checkUrl(excludePaths, path)) {
            return chain.filter(exchange);
        }

AuthProperties中放的就是自定义好的不需要拦截的路径。这里需要的是将当前请求的路径与不需要拦截的路径进行匹配,True就放行。自定义一个匹配方法并使用Spring提供的AntPathMatcher进行路径匹配。

(放行:网关内部有很多个拦截过滤器,是依次执行调用的,实际上是调用下一个拦截器,然后将当前请求响应的上下文对象exchange传递过去)

2,如果需要拦截,就获取请求中的token信息进行校验

不仅要验证获取请求头中是否有相应字段,还要验证token是否有结果,以及是否能够成功解析,不管哪一步失败了,我们就向客户端响应失败的信息(响应状态码)。setComplete() 方法表示响应已完成。它会立即返回并结束当前请求的处理流程,不再执行后续的过滤器或业务逻辑。setComplete() 的返回值是一个 Mono<Void>,这是 Reactor 中的一个信号,表示响应结束。

java 复制代码
String token = null;
        List<String> authorization = request.getHeaders().get("authorization");
        if (authorization != null && !authorization.isEmpty()) {
            token = authorization.get(0);
        }

        // 校验 token
        Long parseToken=null;
        if (token != null && !token.isEmpty()) {
             parseToken = jwtTool.parseToken(token);
            if (parseToken == null) {
                // Token 校验失败,返回 401 未授权
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
        } else {
            // Token 为空,返回 401 未授权
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

此时访问8080/items/page有结果,因为它无需拦截:

访问另外一个被拦截的就没有结果8080/carts:

相关推荐
碎梦归途2 分钟前
23种设计模式-创建型模式之单例模式(Java版本)
java·开发语言·jvm·单例模式·设计模式
Yvonne9784 分钟前
Java八种常见的设计模式
java·设计模式
爱编程的鱼19 分钟前
C# 数据类型||C# 类型转换
java·算法·c#
一键三联啊20 分钟前
ArrayList的subList的数据仍是集合
java·开发语言
前鼻音太阳熊27 分钟前
【Spring Boot 应用开发】-06 自动配置-生成配置元数据
java·spring boot·后端
purrrew27 分钟前
【数据结构_8】栈和队列
java·开发语言·数据结构
汤永红29 分钟前
windows下git bash安装SDKMan报错Looking for unzip...Not found
java·git·sdkman
云惠科技(SEO)1 小时前
泛目录站群技术架构演进观察:2025年PHP+Java混合方案实战笔记
java·人工智能·搜索引擎
牛马baby1 小时前
Springboot 自动装配原理是什么?SPI 原理又是什么?
java·spring boot·后端
小小深2 小时前
了解JVM
java·jvm