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

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

相关推荐
程序员张32 小时前
Maven编译和打包插件
java·spring boot·maven
ybq195133454313 小时前
Redis-主从复制-分布式系统
java·数据库·redis
weixin_472339464 小时前
高效处理大体积Excel文件的Java技术方案解析
java·开发语言·excel
灵犀学长4 小时前
EasyExcel之SheetWriteHandler:解锁Excel写入的高阶玩法
spring boot·excel
小毛驴8504 小时前
Linux 后台启动java jar 程序 nohup java -jar
java·linux·jar
zwjapple4 小时前
docker-compose一键部署全栈项目。springboot后端,react前端
前端·spring boot·docker
DKPT5 小时前
Java桥接模式实现方式与测试方法
java·笔记·学习·设计模式·桥接模式
好奇的菜鸟6 小时前
如何在IntelliJ IDEA中设置数据库连接全局共享
java·数据库·intellij-idea
DuelCode7 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
优创学社27 小时前
基于springboot的社区生鲜团购系统
java·spring boot·后端