【微服务】网关(详细知识以及登录验证)

news2024/9/21 3:37:35

微服务网关

  • 网关
    • 网关路由
      • 快速入门
      • 路由属性
    • 路由断言
    • 网关登录校验
      • 自定义过滤器
      • 实现登录校验
      • 网关传递用户
      • OpenFeign传递用户

网关

网络的关口,负责请求的路由,转发,身份校验

当我们把一个单体项目分成多个微服务并部署在多台服务器中,这时由于地址的不同,可能出现身份校验,地址过多等问题

我们通过网关,将微服务集群统一在一个网关之下,并在通过注册中心将服务拉取到网关之中,自此我们直接访问网关,由网关进行对应微服务的路由转发和身份校验

在SpringCloud中网关的实现包括两种:
Spring Cloud Gateway:基于WebFlux响应式编程,无需调优即可获取优异性能
Netflix:基于Servlet的阻塞式编程,需要调优才能获取与SpringCloudGateway类似的性能

网关路由

快速入门

网关判断由哪个微服务进行处理的过程就是网关路由

  1. 引入依赖网关,Nacos,Loadbalancer
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
  1. 创建一个新的网关微服务模块,并创建启动类
@SpringBootApplication
public class GatewayApplication{
      public static void main(String[] args){
      SpringApplication.run(GatewayApplication.Class,args);
      }
}
  1. 配置网关配置
server:
   port: 8080
spring:
   application:
      name: gateway
   cloud:
      nacos:
        server-addr: 服务器地址:8848
      gateway:
        routes:
          -id: 对应的服务名称
          uri: lb://服务名称  # lb意思是负载均衡
          predicates:
            - Path=/路径名称/**
          # 配置多个路由
          -id:

路由属性

网关路由对应的java类型是RouteDefinition,其中常见的属性:
id:路由的唯一标识
uri:路由的目标地址
predicates:路由断言,判断请求是否符合当前路由
filters:路由过滤器,对请求或响应做特殊处理

路由断言

Spring提供了12种基本的RoutePredicateFactory实现:
在这里插入图片描述
网关提供了很多的路由过滤器,每种过滤器都有独特的作用:
在这里插入图片描述
对应的过滤器可以在配置文件中进行配置

网关登录校验

在这里插入图片描述
此处为网关内部的处理逻辑,我们要进行登录校验的处理需要在过滤器的最前面添加一个自定义的过滤器,在pre阶段进行登录校验
校验成功之后,网关如何将信息传递给微服务:

将用户信息保存到请求头当中进行传递

微服务之间该如何传递校验信息:

也是保存信息到请求头当中,但是请求头的发送是由Openfeign来实现的

自定义过滤器

网关过滤器有两种:
GatewayFilter:路由过滤器,作用于任意指定的路由,默认不生效,要配置到路由后生效(在配置文件中进行配置)
GlobalFilter:全局过滤器,作用范围是所有路由,声明后自动生效(自定义之后在配置文件中使用)
我们这里通过GlobalFilter进行登录校验的实现

public interface GlobalFilter{
      Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain);
}

通过这个方法实现过滤器中的操作,第一个参数是请求上下文,包含整个过滤器链中的共享数据,比如request,response等等,第二个参数是过滤器链,当前过滤器执行完成之后,要调用过滤器中的下一个过滤器

网关采用非阻塞式的编程,Mono中编写一个回调函数,当过滤器将来执行到POST的时候调用回调函数,过滤器将不再进行长时间的等待

我们实现该接口实现过滤器:

@Component
public class MyGlobalFilter implements GlobalFilter,Ordered{
      @Override
      public Mono<void> filter(ServerWebExchange exchange,GatewayFilterChain chain){
      //利用exchange进行登录校验的逻辑编写
      //方向,将共享数据传递给下一个过滤器中
      return chain.filter(exchange);
      }
      @Override
      public int getOrder(){
           return 0;
      }
}

注意:查看过滤器链,将鼠标放在GlobalFilter上按ctrl+H

实现Ordered接口,重写getOrder方法,返回的值越小,则过滤器在过滤器链中的优先级越高

自定义之后在配置文件中进行配置使用:

spring:
   cloud:
      gateway:
        default-filters:
        -AddRequestHeader=a,b

通常我们使用上述的自定义过滤器,但是还有一种过滤器GatewayFilter自定义过滤器,使用过滤器工厂AbstractGateWayFilterFactory:

@Component
public class GLQFilterFactory extends AbstractGatewayFilterFactory<Object>{
    @Override
    public GatewayFilter apply(Object config){
     return new GatewayFilter(new GatewayFilter(){
       @Override
       public Mono<void> filter(ServerWebExchange exchange,GatewayFilterChain chain){
          //编写过滤器逻辑
          //放行
          return chain.filter(exchange);
       }
     }1);
    }
}

自定义过滤器类的类名的前缀就是将来的过滤器的名字,而后半部分应该是类名

实现登录校验

在这里插入图片描述

@Component
public class AuthGlobalFilter implements GlobalFilter,Ordered{
     //不用登录校验的地址实体类
     private final AuthProperties authproperties;
     private final JWtTool jwttool;
     //spring提供的匹配工具类
     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> headers=request.getHeaders().get("token");
       if(headers !=null && !headers.isEmply()){
         token=headers.get(0);
       }
       //利用jwt工具类校验token
       try{
       Long userid=jwttool.parseToken(token);
         }catch (UnauthorizedException e){
             //拦截设置响应状态码为401(未登录)
             ServerHttpResponse response=exchange.getResponse();
             response.setStatusCode(HttpStatus.UNAUTHORIZED);
         }
         //放行
         return chain.filter(exchange);
     }
     private  boolean isExclude(String path){
      for(String pathPattern : authProperties.getExcludePaths()){
         if(antPathMatcher.match(pathPattern,path)){
           return true;
         }
      }
      return false;
     }
           @Override
      public int getOrder(){
           return 0;
      }
}

网关传递用户

前面所将的需要将信息传递给的微服务,需要将信息保存到请求头中,而在微服务中需要设置拦截器将所有用户信息保存到ThreadLocal中

如何向微服务中进行传递,需要略微修改上述所讲的过滤器:

     @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> headers=request.getHeaders().get("token");
       if(headers !=null && !headers.isEmply()){
         token=headers.get(0);
       }
       //利用jwt工具类校验token
       try{
       Long userid=jwttool.parseToken(token);
         }catch (UnauthorizedException e){
             //拦截设置响应状态码为401(未登录)
             ServerHttpResponse response=exchange.getResponse();
             response.setStatusCode(HttpStatus.UNAUTHORIZED);
         }
         //保存到请求头中,传递给微服务
         String userinfo=userid.toString();
         ServerWebExchange ww=exchange.mutate()
                            .request(builder->builder.header("user-info",userinfo))
                            .build();
         //放行
         return chain.filter(ww);
     }

将拦截器单独写在一个微服务当中,这样避免代码冗余:

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

创建好之后在继承了WebMvcConfigurer的配置类中添加拦截器
这时别的微服务还是用不了拦截器,因为它配置类的包没有被扫到,这时我们需要将添加拦截器的配置类放到resources目录下的META-INF文件中添加配置类

@Configuration
@ConditionalOnClass(DispatcherServlet.class)
public class MvcConfig implements WebMvcConfigurer{ 
       @Override
       public void addInterceptors(InterceptorRegistry registry){
          registry.addInterceptor(new UserInfoInterceptor());
       }
}

注意:如果运行的时候网关模块报错

是因为网关的底层不是SpringMVC,而是响应式编程,而WebMvcConfigurer是MVC中提供的,所以我们在配置类上方添加注解,当有MVC的核心api就是DispatcherServlet,拥有这个的微服务该配置类生效

OpenFeign传递用户

微服务项目中的很多业务要被多个微服务共同合作完成,而这个过程中也需要传递登录用户信息
openFeign中提供了一个拦截器接口,所有有Openfeign发起的请求都会先调用拦截器处理请求

将此拦截器写在当时定义的Openfeign的微服务项目中,以便日后统一调用

public class Myconfig{
   @Bean
   public RequestInterceptor userinterceptor(){
      return new RequestInterceptor(){
         @Override
         public void apply(RequestTemplate template){
           //将添加请求头信息
           Long userid=Usercontext.getUser();
           if(userid!=null){
               template.header("user-info",userid.toString()) ;
           }
         }
      }
   }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1646094.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

辐射类案例分析

辐射类案例分析 1.1 接地对辐射实验的影响 金属外壳接地已经成为了一种共识&#xff0c;很多人可能会认为金属外壳就该接地&#xff0c;接地可以改善EMC性能&#xff0c;对于抗干扰类实验&#xff0c;情况可能是这样&#xff0c;但是对于辐射类实验而言&#xff0c;有时候会有…

人工智能概述与入门基础简述

人工智能&#xff08;AI&#xff09;是计算机科学的一个分支&#xff0c;它致力于创建能够执行通常需要人类智能的任务的机器。这篇科普文章将全面介绍人工智能的基本概念、发展历程、主要技术、实际应用以及如何入门这一领域。 一、人工智能的定义与发展历程 人工智能的概念…

【C++】 认识多态 + 多态的构成条件详细讲解

前言 C 目录 1. 多态的概念2 多态的定义及实现2 .1 虚函数&#xff1a;2 .2 虚函数的重写&#xff1a;2 .2.1 虚函数重写的两个例外&#xff1a; 2 .3 多态的两个条件&#xff08;重点&#xff09;2 .4 析构函数为啥写成虚函数 3 新增的两个关键字3.1 final的使用&#xff1a;3…

笔记86:关于【#ifndef + #define + #endif】的用法

当你在编写一个头文件&#xff08;例如 pid_controller.h&#xff09;时&#xff0c;你可能会在多个源文件中包含它&#xff0c;以便在这些源文件中使用该头文件定义的函数、类或其他声明。如果你在多个源文件中都包含了同一个头文件&#xff0c;那么当你将整个工程统一编译&am…

HFSS学习-day1-T形波导的内场分析和优化设计

入门实例--T形波导的内场分析和优化设计 HFSS--此实例详细步骤1.创建项目2.设置求解类型3.设置与建模相关的一些信息设置默认的建模长度单位 4.创建T形模型的三个臂基本参数端口激励进行复制 5.创建被挖去的部分设置正确的边界条件和端口激励方式添加求解设置添加扫频项检查一下…

2010-2022年上市公司彭博ESG披露评分、分项得分数据

2010-2022年上市公司彭博ESG披露评分、分项得分数据 1、时间&#xff1a;2010-2022年 2、来源&#xff1a;Bloomberg ESG 指数 3、指标&#xff1a;股票代码、股票简称、年份、ESG披露评分、环境披露评分、社会信息披露评分、治理披露评分 4、范围&#xff1a;上市公司 5、…

服务运营 | 精选:快递小哥几点到?送货上门服务中的优化问题

推文作者信息&#xff1a;杨春苇&#xff0c;香港城市大学系统工程系在读博士生&#xff0c;研究方向: 专注于线上平台的服务运营管理&#xff0c;涵盖匹配、定价、调度和路径规划等问题。通过将数据科学与运筹优化相结合&#xff0c;提供高效实用的决策支持系统。​ ​ 编者按…

Ps 中 曲线和色阶的区别在哪里?

【官方解释】 在Photoshop中&#xff0c;曲线&#xff08;Curves&#xff09;和色阶&#xff08;Levels&#xff09;是两种调整图像色调和对比度的工具&#xff0c;它们有一些相似之处&#xff0c;但也有一些重要的区别。 调整方式: 曲线&#xff08;Curves&#xff09;&…

使用Docker安装Jenkins

大家好&#xff0c;今天给大家分享如何使用docker安装jenkins&#xff0c;关于docker的安装和常用命令可以参考下面两篇文章&#xff0c;使用docker可以提高资源利用率&#xff0c;能够在不同的环境中轻松迁移和部署应用&#xff0c;在本文中就不过多赘述了。 Docker常用命令 …

Linux字符设备驱动(二) - 与设备驱动模型的关系

一&#xff0c;从/dev目录说起 从事Linux嵌入式驱动开发的人&#xff0c;都很熟悉下面的一些基础知识&#xff0c; 比如&#xff0c;对于一个char类型的设备&#xff0c;我想对其进行read wirte 和ioctl操作&#xff0c;那么&#xff1a; 1&#xff09;我们通常会在内核驱动中…

牛客热题:单链表排序

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题&#xff1a;单链表排序题目链接方法一&…

设计网页用什么软件

在设计网页时&#xff0c;可以使用多种软件来完成不同的任务。以下是一些常用的网页设计软件&#xff0c;以及它们的特点和用途。 1. Adobe Photoshop&#xff1a; Adobe Photoshop 是一款功能强大的图像编辑软件。在网页设计中&#xff0c;它常用于创建和编辑网页所需的图像、…

[Unity常见小问题]打包ios后无法修改模型透明度

问题 在Editor下可以使用如下代码去修改模型的材质的透明度&#xff0c;但是打包ios后无法对透明度进行修改且没有任何warning和error using System.Collections; using System.Collections.Generic; using UnityEngine;public class NewBehaviourScript : MonoBehaviour {[R…

第三篇、利用潜空间生成超稳定动画

1、使用temporal-kit&#xff0c;生成拼接的图片 sides填写3&#xff0c;Height Resolution要填写原视频高度 * sides ,这里也就是三倍 因为原视频动作很快&#xff0c;frames per keyframe填写了2 发现在temp1目录的Input目录下生成了 3* 3的拼接图片 2、到图生图界面&#…

AVL树浅谈

前言 大家好&#xff0c;我是jiantaoyab&#xff0c;本篇文章给大家介绍AVL树。 基本概念 AVL树&#xff08;Adelson-Velsky和Landis树&#xff09;是一种自平衡的二叉搜索树&#xff0c;得名于其发明者G. M. Adelson-Velsky和E. M. Landis。在AVL树中&#xff0c;任何节点的…

【云原生】Pod 的生命周期(一)

【云原生】Pod 的生命周期&#xff08;一&#xff09;【云原生】Pod 的生命周期&#xff08;二&#xff09; Pod 的生命周期&#xff08;一&#xff09; 1.Pod 生命期2.Pod 阶段3.容器状态3.1 Waiting &#xff08;等待&#xff09;3.2 Running&#xff08;运行中&#xff09;3…

蓝牙连接手机播放音乐的同时传输少量数据,那些蓝牙芯片可以实现呢

简介 蓝牙连接手机播放音乐的同时连接另一蓝牙芯片传输少量数据&#xff0c;那些蓝牙芯片可以实现呢&#xff1f; 这个需求&#xff0c;其实就是双模的需求 简单描述就是:播放音乐的同时&#xff0c;还可以连接ble&#xff0c;进行数据的传输。二者同时进行&#xff0c;互不…

Apache.commons.lang3 的 isNumber 将会在 lang 4 的时候丢弃

在判断输入的字符串是不是一个数字的时候&#xff0c;我们通常用的最多的方法就是 &#xff1a; NumberUtils.isNumber("12"); 但是这个方法将会在 Lang 4.0 版本中被丢弃。 可以使用的替代方法为&#xff1a;isCreatable(String) 通过查看源代码&#xff0c;我们…

ASP.NET网上图书预约系统的设计

摘 要 《网上图书预约系统的设计》是以为读者提供便利为前提而开发的一个信息管理系统&#xff0c;它不仅要求建立数据的一致性和完整性&#xff0c;而且还需要应用程序功能的完备、易用等特点。系统主要采用VB.NET作为前端的应用开发工具&#xff0c;利用SQL Server2000数据…

7zip如何只压缩文件不带上级目录?

在使用7zip进行文件压缩的时候&#xff0c;如果直接选择要压缩的文件进行压缩&#xff0c;得到的压缩包则会多包含一层顶层目录&#xff0c;解压缩之后需要点击两次才能进入到实际目录中&#xff0c;为了解决这个问题&#xff0c;本文根据探索找到了一种解决办法。 如下是一个演…