实现流程
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:用户服务,对外暴露用户操作相关接口,如新增用户等
搭建父项目工程jwt-parent
创建项目
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>
启动Nacos注册中心
我这里启动是单节点模式
启动之后可以去页面访问Nacos,http://localhost:8845/nacos
其他模块搭建
创建jwt-common模块
创建项目
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>
加入工具类
项目结构
创建jwt-pojo模块
创建项目
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>
创建实体类
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;
}
搭建goods-search
功能分析
1、用户未登陆状态,可以搜索商品信息
2、goods-search为商品搜索服务,接收用户页面搜索请求
实现步骤:
1、pojo
2、controller
4、service
5、dao
创建项目
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>
bootstrap.yml配置
spring:
application:
name: goods-service
profiles:
active: dev
cloud:
nacos:
server-addr: localhost:8845
config:
file-extension: yaml
server:
port: 7000
功能实现
模拟商品搜索功能
启动类
@SpringBootApplication
public class GoodsSearch01Application {
public static void main(String[] args) {
SpringApplication.run(GoodsSearch01Application.class, args);
}
}
功能测试
搭建user-service服务
功能分析
提供用户操作相关的接口
搭建项目
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>
bootstrap.yml
spring:
application:
name: userservice
profiles:
active: dev
cloud:
nacos:
server-addr: localhost:8848
config:
file-extension: yaml
server:
port: 8000
功能实现
提供用户新增接口
启动类
@SpringBootApplication
public class UserService01Application {
public static void main(String[] args) {
SpringApplication.run(UserService01Application.class, args);
}
}
功能测试
我这里拿的是PostMan测试,如果你们有自己的其他测试工具都可以,想学Postman使用的去我博客瞅瞅,有一篇
授权中心jwt-auth
授权中心的主要职责:
-
用户鉴权:
- 接收用户的登录请求,通过用户中心的接口进行校验,通过后生成JWT
- 使用私钥生成JWT并返回
-
服务鉴权:微服务间的调用不经过Zuul,会有风险,需要鉴权中心进行认证
- 原理与用户鉴权类似,但逻辑稍微复杂一些(此处我们不做实现)
因为生成jwt,解析jwt这样的行为以后在其它微服务中也会用到,因此我们会抽取成工具。我们把鉴权中心进行聚合,一个工具module,一个提供服务的module
创建授权中心
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>
bootstrap.yml
spring:
application:
name: authservice
profiles:
active: dev
cloud:
nacos:
server-addr: localhost:8845
config:
file-extension: yaml
server:
port: 9000
功能实现
提供登录接口
启动类
@SpringBootApplication
public class JwtAuth01Application {
public static void main(String[] args) {
SpringApplication.run(JwtAuth01Application.class, args);
}
}
功能测试
Zuul网关jwt-gateway
功能分析
- 1、对所有请求进行过滤
- 2、如果用户发起的是登录操作或者是商品搜索操作,放行
- 3、如果用户发起的是对user-service服务的操作,获取并解析token,如果token存在且有效,放行;否则响应错误页面
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>
yml文件
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8845 # 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/**
功能实现
- 编写鉴权过滤器
@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();
}
}
功能测试
- 商品搜索(未登录)
- 用户新增(未登录)
- 携带token,进行用户新增
这样我们就完成了鉴权!!