1.JWT
1.0 为什么要学习JWT?
1.1.简介
JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;它是分布式服务权限控制的标准解决方案!
它跟RBAC的区别:两者不冲突,在项目中后台权限服务的数据库设计使用RBAC,而前端项目访问后台微服务的权限校验使用jwt
.
GitHub上jwt的java客户端:https://github.com/jwtk/jjwt
什么是token:https://www.cnblogs.com/xuxinstyle/p/9675541.html
1.2.数据格式
普通的token:32位UUID
JWT的token:至少64位
JWT的token包含三部分数据:
- Header:头部,通常头部有两部分信息:
- 声明类型type,这里是JWT(type=jwt)
- 加密算法,自定义(rs256/base64/hs256)
我们会对头部进行base64加密(可解密),得到第一部分数据
- Payload:载荷,就是有效数据,一般包含下面信息:
- 用户身份信息-userid,username(注意,这里因为采用base64加密,可解密,因此不要存放敏感信息)
- 注册声明:如token的签发时间,过期时间,签发人等
这部分也会采用base64加密,得到第二部分数据 - Signature:base64加密,签名,是整个数据的认证信息。一般根据前两步的数据,再加上服务的的密钥(secret,盐)(不要泄漏,最好周期性更换),通过加密算法生成。用于验证整个数据完整和可靠性
结论:
1 jwt的一个有规则的token
2 它有三部分组成:Header.payload.signature,每部分都是通过base64加密而成的
3 jwt每个部分都是可以解密的
1.3. JWT详解
1.3.1 base64编码原理(了解)
Base64编码之所以称为Base64,是因为其使用64个字符来对任意数据进行编码,同理有Base32、Base16编码。标准Base64编码使用的64个字符如下:
这64个字符是各种字符编码(比如ASCII码)所使用字符的子集,并可打印。唯一有点特殊的是最后两个字符。
Base64本质上是一种将二进制数据转成文本数据的方案。对于非二进制数据,是先将其转换成二进制形式,然后每连续6比特(2的6次方=64)计算其十进制值,根据该值在上面的索引表中找到对应的字符,最终得到一个文本字符串。假设我们对Hello!进行Base64编码,按照ASCII表,其转换过程如下图所示:
可知Hello!的Base64编码结果为SGVsbG8h,原始字符串长度为6个字符串,编码后长度为8个字符,每3个原始字符经编码成4个字符。
但要注意,Base64编码是每3个原始字符编码成4个字符,如果原始字符串长度不能被3整除,怎么办?使用0来补充原始字符串。
以Hello!!为例,其转换过程为:
Hello!!
Base64编码的结果为 SGVsbG8hIQAA
。最后2个零值只是为了Base64编码而补充的,在原始字符中并没有对应的字符,那么Base64编码结果中的最后两个字符 AA
实际不带有效信息,所以需要特殊处理,以免解码错误。
标准Base64编码通常用 =
字符来替换最后的 A
,即编码结果为 SGVsbG8hIQ==
。因为 =
字符并不在Base64编码索引表中,其意义在于结束符号,在Base64解码时遇到 =
时即可知道一个Base64编码字符串结束。
如果Base64编码字符串不会相互拼接再传输,那么最后的 =
也可以省略,解码时如果发现Base64编码字符串长度不能被4整除,则先补充 =
字符,再解码即可。
解码是对编码的逆向操作,但注意一点:对于最后的两个 =
字符,转换成两个A
字符,再转成对应的两个6比特二进制0值,接着转成原始字符之前,需要将最后的两个6比特二进制0值丢弃,因为它们实际上不携带有效信息。
总结:
1、base64的编码/加密原理
答:原理:将键盘输入的字符用base64编码表示
过程:将键盘输入字符的ascii码值,转成的对应8位二进制,将该二进制6个一组拆分,并计算拆分之后的十进制值,找出十进制值在base64编码表中对应的字母,即完成base64加密
1.3.2 jwt测试-JwtUtil的使用
- 导入jar包
<properties> <jjwt.version>0.7.0</jjwt.version> <joda-time.version>2.9.6</joda-time.version> </properties> <dependencies> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jjwt.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/joda-time/joda-time --> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>${joda-time.version}</version> </dependency> </dependencies>
- 导入JwtUtil
package com.czxy.util; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.joda.time.DateTime; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; import java.security.Key; /** * @ClassName: JwtHelper * @Description: token工具类 * @author: yuanxinqi * @date: 2021/8/17 9:59 * @version: V 2.0.0 * @since: (jdk_1.8) */ public class JWTUtil { /** * 获取token中的参数 * * @param token * @return */ public static Claims parseToken(String token,String key) { if ("".equals(token)) { return null; } try { return Jwts.parser() .setSigningKey(DatatypeConverter.parseBase64Binary(key)) .parseClaimsJws(token).getBody(); } catch (Exception ex) { return null; } } /** * 生成token * * @param userId * @return */ public static String createToken(Integer userId,String username,String key, int expireMinutes) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //生成签名密钥 byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(key); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); //添加构成JWT的参数 JwtBuilder builder = Jwts.builder() // .setHeaderParam("type", "JWT") // .setSubject(userId.toString()) .claim("userId", userId) // 设置载荷信息 .claim("username",username) .claim("age",23) .setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate())// 设置超时时间 .signWith(signatureAlgorithm, signingKey); //生成JWT return builder.compact(); } public static void main(String[] args) { String token = JWTUtil.createToken(1, "zhangsan","admin", 30); System.out.println(token); Claims claims = JWTUtil.parseToken(token, "admin"); System.out.println(); } }
- 编码测试
结论:
- jwt是采用base64加密/编码的
- jwt的每个部分都是可以单独解码的
- 在jwt中不应存放重要明感信息,因为可以解密,不安全
- createToken源码跟踪–最重要的方法
1.4.JWT交互流程
流程图:
.
步骤翻译:
• 1、用户登录
• 2、服务的认证,通过后根据secret生成token
• 3、将生成的token返回给用户
• 4、用户每次请求携带token
• 5、服务端利解读jwt签名,判断签名有效后,从Payload中获取用户信息
• 6、处理请求,返回响应结果
因为JWT签发的token中已经包含了用户的身份信息,并且每次请求都会携带,这样服务的就无需保存用户信息,甚至无需去数据库查询,就能知道用户身份,完全符合了Rest的无状态规范。
1.5.结合Zuul的鉴权流程
我们逐步演进系统架构设计。需要注意的是:secret是签名的关键,因此一定要保密,我们放到鉴权中心保存,其它任何服务中都不能获取secret。
在微服务架构中,我们可以把服务的鉴权操作放到网关中,将未通过鉴权的请求直接拦截,如图:
流程图解:
- 第一个流程:用户点击登录—>请求授权中心颁发jwt凭证
- 第二个流程:用户的每次请求都携带jwt凭证—>zuul判断jwt是否正确
• 1、用户请求登录
• 2、Zuul将请求转发到授权中心,请求授权
• 3、授权中心校验完成,颁发JWT凭证
• 4、客户端请求其它功能,携带JWT
• 5、Zuul将jwt交给授权中心校验,通过后放行
• 6、用户请求到达微服务
• 7、微服务将jwt交给鉴权中心,鉴权同时解析用户信息
• 8、鉴权中心返回用户数据给微服务
• 9、微服务处理请求,返回响应
- jwt-parent:统一jar包版本控制
- jwt-pojo:实体类存放位置
- jwt-common:工具类、常量类等存放的位置
- jwt-auth:认证中心
- goods-search:商品搜索服务,对外暴露商品搜索相关接口
- user-service:用户服务,对外暴露用户操作相关接口,如新增用户等
结论:
- 项目的整体架构方式
- 搭建认证中心
- 授权中心
- 通过zuul进行权限过滤
3. 搭建父工程jwt-parent
3.1 创建项目
3.2 pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.czxy</groupId> <artifactId>jwt-parent</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <name>jwt-parent</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR10</spring-cloud.version> <mybatis.starter.version>2.1.1</mybatis.starter.version> <mapper.starter.version>1.2.3</mapper.starter.version> <druid.starter.version>1.1.9</druid.starter.version> <mysql.version>5.1.32</mysql.version> <pageHelper.starter.version>1.2.3</pageHelper.starter.version> <jjwt.version>0.7.0</jjwt.version> <joda-time.version>2.9.6</joda-time.version> <lombok.version>1.18.18</lombok.version> </properties> <!-- dependencyManagement 这个标签一般用在父项目中,他不是导入jar包的标签,只是用来限定jar包版本的标签 然后子项目依赖当前父项目,在子项目中导入需要的jar包坐标 子项目无需填入版本号,完全由父项目控制 --> <dependencyManagement> <dependencies> <!-- springCloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!-- mybatis启动器 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.starter.version}</version> </dependency> <!-- 通用Mapper启动器 --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>${mapper.starter.version}</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pageHelper.starter.version}</version> </dependency> <!-- druid启动器 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.starter.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jjwt.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/joda-time/joda-time --> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>${joda-time.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
4. 启动Nacos注册中心
略。
5.准备工作
5.1 创建jwt-common模块
5.1.1 创建项目
5.1.2 pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>jwt-parent</artifactId> <groupId>com.czxy</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jwt-common</artifactId> <dependencies> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/joda-time/joda-time --> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> </project>
5.1.3 加入工具类
5.2 创建jwt-pojo模块
5.2.1 创建项目
5.2.2 POM
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>jwt-parent</artifactId> <groupId>com.czxy</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jwt-pojo</artifactId> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> </project>
5.2.3 创建实体类
Goods商品实体类
@Data @AllArgsConstructor @NoArgsConstructor public class Goods { private Integer skuid; private String goodsName; private Double price; }
User实体类
@Data @AllArgsConstructor @NoArgsConstructor public class User { private Integer id; private String username; private String password; }
6. 搭建goods-search
6.1 功能分析
1、用户未登陆状态,可以搜索商品信息
2、goods-search为商品搜索服务,接收用户页面搜索请求
实现步骤:
1、pojo
2、controller
4、service
5、dao
6.2 创建项目
6.3 pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.czxy</groupId> <artifactId>jwt-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>goods-search</artifactId> <packaging>jar</packaging> <name>goods-search</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>com.czxy</groupId> <artifactId>jwt-pojo01</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>com.czxy</groupId> <artifactId>jwt-common01</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mybatis--> <!-- <dependency>--> <!-- <groupId>org.mybatis.spring.boot</groupId>--> <!-- <artifactId>mybatis-spring-boot-starter</artifactId>--> <!-- </dependency>--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--nacos配置管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
6.4 bootstrap.yml配置
spring: application: name: goods-service profiles: active: dev cloud: nacos: server-addr: localhost:8848 config: file-extension: yaml server: port: 7000
6.5 功能实现
模拟商品搜索功能
6.6 启动类
@SpringBootApplication public class GoodsSearch01Application { public static void main(String[] args) { SpringApplication.run(GoodsSearch01Application.class, args); } }
6.7 功能测试
7 搭建user-service服务
7.1 功能分析
- 1、提供用户操作相关的接口
7.2 搭建项目
7.3 pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.czxy</groupId> <artifactId>jwt-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>user-service</artifactId> <packaging>jar</packaging> <name>user-service</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>com.czxy</groupId> <artifactId>jwt-pojo01</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>com.czxy</groupId> <artifactId>jwt-common01</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mybatis--> <!-- <dependency>--> <!-- <groupId>org.mybatis.spring.boot</groupId>--> <!-- <artifactId>mybatis-spring-boot-starter</artifactId>--> <!-- </dependency>--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--nacos配置管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
7.4 bootstrap.yml
spring: application: name: userservice profiles: active: dev cloud: nacos: server-addr: localhost:8848 config: file-extension: yaml server: port: 8000
7.5 功能实现
- 提供用户新增接口
7.6 启动类
@SpringBootApplication public class UserService01Application { public static void main(String[] args) { SpringApplication.run(UserService01Application.class, args); } }
7.7 功能测试
8. 授权中心jwt-auth
授权中心的主要职责:
- 用户鉴权:
- 接收用户的登录请求,通过用户中心的接口进行校验,通过后生成JWT
- 使用私钥生成JWT并返回
- 服务鉴权:微服务间的调用不经过Zuul,会有风险,需要鉴权中心进行认证
- 原理与用户鉴权类似,但逻辑稍微复杂一些(此处我们不做实现)
因为生成jwt,解析jwt这样的行为以后在其它微服务中也会用到,因此我们会抽取成工具。我们把鉴权中心进行聚合,一个工具module,一个提供服务的module
8.1 创建授权中心
8.2 pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.czxy</groupId> <artifactId>jwt-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>jwt-auth</artifactId> <packaging>jar</packaging> <name>jwt-auth</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>com.czxy</groupId> <artifactId>jwt-pojo01</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>com.czxy</groupId> <artifactId>jwt-common01</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mybatis--> <!-- <dependency>--> <!-- <groupId>org.mybatis.spring.boot</groupId>--> <!-- <artifactId>mybatis-spring-boot-starter</artifactId>--> <!-- </dependency>--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--nacos配置管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
8.3 bootstrap.yml
spring: application: name: authservice profiles: active: dev cloud: nacos: server-addr: localhost:8848 config: file-extension: yaml server: port: 9000
8.4 功能实现
- 提供登录接口
8.5 启动类
@SpringBootApplication public class JwtAuth01Application { public static void main(String[] args) { SpringApplication.run(JwtAuth01Application.class, args); } }
8.6 功能测试
9. Zuul网关jwt-gateway
9.1 功能分析
- 1、对所有请求进行过滤
- 2、如果用户发起的是登录操作或者是商品搜索操作,放行
- 3、如果用户发起的是对user-service服务的操作,获取并解析token,如果token存在且有效,放行;否则响应错误页面
9.2 搭建jwt-zuul项目
9.3 pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>jwt-parent</artifactId> <groupId>com.czxy</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jwt-zuul</artifactId> <dependencies> <!--网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--nacos服务发现依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
9.4 yml
server: port: 10010 # 网关端口 spring: application: name: gateway # 服务名称 cloud: nacos: server-addr: localhost:8848 # nacos地址 gateway: routes: # 网关路由配置 - id: goods-service # 路由id,自定义,只要唯一即可 # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址 uri: lb://goodsservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称 predicates: # 路由断言,也就是判断请求是否符合路由规则的条件 - Path=/search/** # 这个是按照路径匹配,只要以/user/开头就符合要求 - id: user-service uri: lb://userservice predicates: - Path=/user/** - id: auth-service uri: lb://authservice predicates: - Path=/auth/**
9.5 功能实现
- 编写鉴权过滤器
@Component @Order(-1) public class JWTFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String url = exchange.getRequest().getURI().getPath(); System.out.println(url); // 1 判断URL if(url.toString().contains("login")){ System.out.println("无需登录,直接放行"); return chain.filter(exchange); } // 2.获取请求参数 // MultiValueMap<String, String> params = exchange.getRequest().getQueryParams(); // // 3.获取authorization参数 // String token = params.getFirst("authorization"); List<String> tokens = exchange.getRequest().getHeaders().get("authorization"); // 4判断是否为空 if(tokens!=null&&(tokens.size()==1)){ // 5 解析token Claims claims = JWTUtil.parseToken(tokens.get(0), "user"); //6 判断解析是否成 if(claims!=null){ //7 成功了,放行 return chain.filter(exchange); } } // 8.拦截 // 8.1.禁止访问,设置状态码 exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); // 8.2.结束处理 return exchange.getResponse().setComplete(); } }
9.6 功能测试
- 商品搜索(未登录)
- 用户新增(未登录)
- 用户登录
- 携带token,进行用户新增