Gateway集成方法以及拦截器和过滤器的使用

前提:请先创建好一个SpringBoot项目 

1. 引入依赖

 SpringCloud 和 alibabaCloud 、 SpringBoot间对版本有强制要求,我使用的springboot是3.0.2的版本。版本对应关系请看:版本说明 · alibaba/spring-cloud-alibaba Wiki · GitHub

    <dependencyManagement>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2022.0.3</version>
        </dependency>
    </dependencyManagement>
    <dependencies>
        <!-- SpringCloud组件之一,不加会提示错误 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>3.1.4</version>
        </dependency>
        <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>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
    </dependencies>

2. 搭建网关

配置bootstrap.yml文件:

server:
  port: 8083
spring:
  application:
    name: big-news-admin-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 你的ip:8848
      config:
        server-addr: 你的ip:8848
        file-extension: yml

 Nacos配置中心:

yml示例:

spring:
  data:
    redis:
      host: localhost
      port: 6379
  cloud:
    gateway:
      globalcors:
        add-to-simple-url-handler-mapping: true
        corsConfigurations:
          '[/**]':
            allowedHeaders: "*"
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTION
      routes:
        # 平台管理
        - id: user
          uri: lb://big-news-user
          predicates:
            - Path=/user/**
        # 分类
        - id: category
          uri: lb://big-news-category
          predicates:
            - Path=/category/**
        # 文章
        - id: article
          uri: lb://big-news-article
          predicates:
            - Path=/article/**
        # 文件
        - id: common
          uri: lb://big-news-common
          predicates:
            - Path=/upload/**
token:
  secretKey: rikka7e7f74ef-62b5-4b29-96ae-c698f7c823c1
  expirationTime: 1080000060

解释:

该配置用于解决跨域问题

路由断言规则,id需唯一,uri中的名称需要对应服务的应用名。path用于匹配路由。

以下图举例:uri意味着将请求匹配到nacos中名叫big-news-user的服务,path意味着根据只要请求携带`user`就匹配服务。

可用 filters 过滤掉请求中的字段,比如下图。意味着最后到服务的实际请求不会携带`user`,你就不需要在controller的接收路径上上写`user`。

 3. 全局过滤器实现jwt校验

思路分析:

  1. 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录

  2. 用户登录成功,后台管理微服务签发JWT TOKEN信息返回给用户

  3. 用户再次进入网关开始访问,网关过滤器接收用户携带的TOKEN

  4. 网关过滤器解析TOKEN ,判断是否有权限,如果有,则放行,如果没有则返回未认证错误  

 3.1 拷贝一份jwt工具类到网关服务

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtUtil {

    private static final String USER_CLAIMS_KEY = "user";

    // 过期时间
    @Value("${token.expirationTime}")
    private long EXPIRE_TIME;

    // 密钥
    @Value("${token.secretKey}")
    private String SECRET;

    /**
     * 创建JWT Token
     *
     * @param payload 载荷(Claims)
     * @return JWT Token
     */
    public String createToken(Map<String, Object> payload) {
        // 1. 创建一个密钥
        SecretKey key = Keys.hmacShaKeyFor(SECRET.getBytes(StandardCharsets.UTF_8));

        // 2. 创建JWT Builder
        // 注意:这里的签名算法不能是 RS256,需要使用 HS256
        io.jsonwebtoken.JwtBuilder builder = Jwts.builder()
                .setClaims(payload)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))
                .signWith(key, SignatureAlgorithm.HS256);

        // 3. 生成JWT Token
        return builder.compact();
    }

    /**
     * 解析JWT Token
     *
     * @param token JWT Token
     * @return 载荷(Claims)
     */
    public Map<String, Object> parseToken(String token) {
        // 1. 获取密钥
        SecretKey key = Keys.hmacShaKeyFor(SECRET.getBytes(StandardCharsets.UTF_8));

        // 2. 解析JWT Token
        Claims claims = Jwts.parser()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();

        // 3. 将Claims里的内容转换成Map
        Map<String, Object> payload = new HashMap<>(claims);
        payload.remove("exp");
        payload.remove("iat");
        payload.remove("iss");
        payload.remove("aud");
        payload.remove("nbf");
        payload.remove("sub");
        payload.remove("jti");

        return payload;
    }

    /**
     * 获取JWT Token的过期时间
     *
     * @param token JWT Token
     * @return 过期时间
     */
    public Date getExpirationDateFromToken(String token) {
        Claims claims = parseClaims(token);
        if (claims != null) {
            return claims.getExpiration();
        }
        return null;
    }

    /**
     * 验证JWT Token是否有效
     *
     * @param token JWT Token
     * @return 是否有效
     */
    public boolean validateToken(String token) {
        try {
            parseClaims(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取payload中的用户信息
     *
     * @param token JWT Token
     * @return 用户信息
     */
    public Map<String, Object> getUserFromToken(String token) {
        Map<String, Object> user = null;
        Claims claims = parseClaims(token);
        if (claims != null) {
            user = (Map<String, Object>) claims.get(USER_CLAIMS_KEY);
        }
        return user;
    }

    /**
     * 解析JWT Token中的Claims
     *
     * @param token JWT Token
     * @return Claims
     */
    public Claims parseClaims(String token) {
        try {
            SecretKey key = Keys.hmacShaKeyFor(SECRET.getBytes(StandardCharsets.UTF_8));
            return Jwts.parser()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            return null;
        }
    }

}

 3.2 网关微服务中新建全局过滤器

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.xin.common.properties.TokenProperties;
import com.xin.common.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Objects;

@Component
public class AuthorizeFilter implements Ordered, GlobalFilter {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //用于接收token的信息,你可按实际请看书写,也可以直接在这个类里定义静态参数。
    //tokenProperties主要包含:密钥key、过期时间
    @Autowired
    private TokenProperties tokenProperties;

    @Autowired
    private JwtUtil jwtUtil;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取请求
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //2.判断是否是登录操作
        if (request.getURI().getPath().contains("/login")) {
            //放行
            return chain.filter(exchange);
        }

        String token = request.getHeaders().getFirst("Authorization");
        //3.若token为空,校验失败
        if (StringUtils.isEmpty(token)){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //结束请求
            return response.setComplete();
        }
        try {
            //4. 解析token
            Claims claims = jwtUtil.parseClaims(token);
            //获得token解析后中的用户信息
            Object o = claims.get("user");
            String user = JSONUtil.toJsonStr(o);
            String id = user.substring(user.indexOf(":")+1, user.indexOf(","));
            //5.判断token是否在redis中过期,或删除
            String object = stringRedisTemplate.opsForValue().get("token:" + id + ":" + token);
            if (Objects.isNull(object)) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //结束请求
                return response.setComplete();
            }


            // 将用户信息存放进 header中
            ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
                httpHeaders.add("user", user + "");
            }).build();
            exchange.mutate().request(serverHttpRequest).build();
        }catch (Exception e){
            e.printStackTrace();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //5.放行
        return chain.filter(exchange);
    }

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

注意,该过滤器只是实现了对Token的校验,并将解析结果存放进header进一步转发。获取user信息,还需在实际的服务里定义拦截器获取:

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String userString = request.getHeader("user");
        Optional<String> optional = Optional.ofNullable(userString);
        if(optional.isPresent()) {
            //把用户存入threadLocal中
            TreadLocalUtil.setUser(userString);
            log.info("设置用户信息到threadlocal中...");
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        TreadLocalUtil.clear();
        log.info("清理threadlocal...");
    }
}

 在WebMvcConfig中配置该拦截器:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
    }
}

最后最后!!!各位看官觉得有用就收藏、点赞、评论一下吧。我看到问题后,我会第一时间回复的! ​​​​​​​ 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows安装npm教程

NPM&#xff08;Node Package Manager&#xff09;是一个用于管理和共享JavaScript代码包的工具。它是Node.js生态系统的一部分&#xff0c;广泛用于构建JavaScript应用程序和库。 以下是NPM的主要功能和用途&#xff1a; 1.代码包管理 NPM允许开发者在项目中安装、更新、卸载…

Bellman_Ford算法总结

知识概览 Bellman_Ford算法适合解决存在负权边的最短路问题&#xff0c;时间复杂度为O(nm)。在存在负权边的最短路问题中&#xff0c;Bellman_Ford算法的效率虽然不如SPFA算法&#xff0c;但是Bellman_Ford算法能解决SPFA算法不能解决的经过不超过k条边的最短路问题。 例题展示…

Java对象内存布局和对象头

Java对象内存布局和对象头 在 HotSpot 虚拟机中&#xff0c;对象在内存中的布局分为三块区域&#xff1a;对象头&#xff0c;实例数据和对齐填充。 对象头中包含两部分&#xff1a;MarkWord 和 类型指针。如果是数组对象的话&#xff0c;对象头还有一部分是存储数组的长度。 …

什么是OAuth2.0

前言 OAuth&#xff08;Open Authorization&#xff09;是一个关于授权&#xff08;authorization&#xff09;的开放网络标准&#xff0c;允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息&#xff0c;而不需要将用户名和密码提供给第三方移动应用或分享他们数…

【python】Ubuntu下安装spyder及matplotlib中文显示

一、查看Ubuntu版本 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.3 LTS Release: 22.04 Codename: jammy尝试用cat /etc/debian_version命令&#xff0c;竟然可以显示出来Debian的版本。 $ cat /etc/debian_version …

北斗三号海上人员落水报警及示位搜救系统

海洋水上作业中&#xff0c;人员落水问题时有发生&#xff0c;过去救援人员很难获取落水人员呼救信息、确定落水人员位置、事故发生时间以及事态严重程度&#xff0c;以给予最及时的救援&#xff0c;管理人员都对此无计可施&#xff0c;缺乏有效技术手段是目前海上事故救援效率…

如何使用JuiceSSH实现手机端远程连接Linux服务器

文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …

2023年小型计算机视觉总结

在过去的十年中&#xff0c;出现了许多涉及计算机视觉(CV)的项目&#xff0c;无论是小型的概念验证项目还是更大规模的生产应用。应用计算机视觉的方法是相当标准化的: 1、定义问题(分类、检测、跟踪、分割)、输入数据(图片的大小和类型、视野)和类别(正是我们想要的) 2、注释…

WEB 3D技术 three.js 通过分组顶点 给同一个物体设置多个材质

上文 WEB 3D技术 three.js 集合体 讲解三角形构建图形 顶点概念 顶点值重用 我们讲到 一个元素是由多个面组成的 那么 我们是不是可以一个物体用多个材质&#xff1f; 简单说 一个面用一种材质 我们还是在官网中搜索 geome 如下图选择 然后 找到 groups 顶点组 它能够将我们的…

Abaqus随机单元删除插件:Random Element Del - AbyssFish

插件介绍 Random Element Del - AbyssFish 插件可在Abaqus软件内对自建网格部件进行指定区域内的随机单元删除&#xff0c;可用于生成指定孔隙率或模拟缺陷等。 插件使用中指定需要进行删除的部件&#xff0c;这里的部件需要为网格部件。设定删除单元的比例参数&#xff08;…

使用Java语言统计一行字符串的数据

方法 创建字符串接收器&#xff0c;接收用户输入的字符串&#xff0c;然后将其转换为字符串数组&#xff0c;安装字符对应的字节码进行判断。 代码 import java.io.*; public class StaticsChar {public static void main(String[] args) throws IOException{String zifuch…

如何使用Docker部署Dashy并无公网ip远程访问管理界面

文章目录 简介1. 安装Dashy2. 安装cpolar3.配置公网访问地址4. 固定域名访问 简介 Dashy 是一个开源的自托管的导航页配置服务&#xff0c;具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。你可以将自己常用的一些网站聚合起来放在一起&#xff0c;形成自己的导航…

2023年全球前端大技术大会(GMTC北京站2023)-核心PPT资料下载

一、峰会简介 大会以“业务至上&#xff0c;效率为王”为主题&#xff0c;策划了 1 个主会场&#xff0c;10 个技术专场。会议议题包含前端 DevOps 实践、低代码、大前端监控、跨端技术选型、团队可持续发展、IoT 动态应用开发、移动端性能与效率优化、TypeScript、大前端技术…

【期末复习】微信小程序复习大纲( 1- 5 章)

前言&#xff1a; 这周开始进入期末复习周&#xff0c;没时间看C/C、linux等知识了&#xff0c;先把期末考试必考的知识捋一遍。 目录 第一章 微信小程序入门 一、填空题 二、判断题 三、选择题 四、简答题 第二章 微信小程序页面制作 一、填空题 二、判…

三叠云工程劳务管理,优化建筑施工管理,提升效率与质量

随着建筑行业的蓬勃发展&#xff0c;工程施工现场管理变得愈发复杂。传统的人员管理方式已经无法满足企业快速发展的需求。如何提高施工效率、优化人力资源管理成为了建筑企业亟待解决的问题。逐渐走向数字化的工程建设行业&#xff0c;急需一种足以匹配这一时代变革、高效管理…

两台苹果手机靠近迁移数据,教你如何一键换机!

我们在更换新手机时&#xff0c;如果没有将旧手机的数据迁移到新手机上&#xff0c;一旦旧手机丢失或者无法正常启动&#xff0c;那么所有数据将会丢失。更换手机后&#xff0c;及时迁移手机数据可以避免数据丢失。那么&#xff0c;两台苹果手机靠近迁移数据怎么操作&#xff1…

k8s:kubernets

自动部署、自动扩展和管理的容器化部署的应用程序的一个开源系统 k8s负责自动化运维管理多个容器化程序的集群&#xff0c;是一个功能强大的容器编排工具 可以以分布式和集群化的方式进行容器管理 1.18版本&#xff0c;目前最多的是1.20版本&#xff0c;最新的是1.29版本&am…

第八部分 函数

定义 8.1 设 F 为二元关系 , 若 ∀ x ∈ dom F 都存在唯一的 y ∈ ran F 使 xFy 成立 , 则称 F 为 函数 对于函数 F , 如果有 xFy , 则记作 y F ( x ), 并称 y 为 F 在 x 的 值 . 例 F 1 {< x 1 , y 1 >,< x 2 , y 2 >,< x 3 , y 2 >…

3 步走,快速上手 API 接口测试

开始 API 接口测试之前&#xff0c;我们需要弄清接口测试的含义&#xff1a; 接口测试就是根据接口清单&#xff0c;模拟客户端向服务端发送请求数据&#xff0c;并获取响应数据后&#xff0c;查看响应数据是否符合预期的过程。 整个过程可以分为三个步骤&#xff1a; 第一步…

Android Termux安装SSH结合内网穿透实现远程SFTP文件传输

文章目录 1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 SFTP&#xff08;SSH File Transfer Protocol&#xff09;是一种基于SSH&#xff08;Secure Shell&#xff09;安全协议的文件传输协议。与FTP协议相比&#xff0c;SFTP使用了…