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

当我们创建好了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:

相关推荐
Percep_gan7 分钟前
idea的使用小技巧,个人向
java·ide·intellij-idea
缘来是庄7 分钟前
设计模式之迭代器模式
java·设计模式·迭代器模式
Liudef0613 分钟前
基于HTML与Java的简易在线会议系统实现
java·前端·html
JosieBook23 分钟前
【Java编程动手学】Java常用工具类
java·python·mysql
oioihoii27 分钟前
C++11标准库算法:深入理解std::none_of
java·c++·算法
老虎06271 小时前
数据结构(Java)--位运算
java·开发语言·数据结构
yanjiaweiya1 小时前
云原生-集群管理续
java·开发语言·云原生
写不出来就跑路1 小时前
暑期实习感悟与经验分享:从校园到职场的成长之路
java·开发语言·经验分享·spring boot
No Silver Bullet1 小时前
软件工程功能点估算法常用术语介绍
java·开发语言·软件工程
泰勒疯狂展开1 小时前
Java研学-MongoDB(二)
java·mongodb