SA-Token授权 鉴权中心微服务
Posted 伟子涵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SA-Token授权 鉴权中心微服务相关的知识,希望对你有一定的参考价值。
授权 鉴权中心微服务
1 什么是JWT
1.2 JWT 的基本概念
1.3 JSON Web Token jwt 是一个开放标准 它定义了一种紧凑的、自包含的方式 用于作为JSON 对象在各方之间安全地传输信息
1.4.那些场景下可以考虑使用JWT ?
1.用户授权 信息交换
1.5 JWT的结构及其含义
1.JWT 由三个部分组成 Header、Payload Signature 且用圆点连接
2.Header 由两部分(Token类型 加密算法名称)组成,并使用Base64 编码
3.Payload kv形式的数据 即你想传递的数据 (授权的话就是token 信息)
4.Signature 为了得到签名部分 你必须有编码过的Header 编码过的payload 一个秘钥 签名算法是Header 中指定的那个 然对它们签名即可
我以前的公司使用的是JWT+SpringSecurity 做的鉴权和权限中心 现在我最近公司的微服务项目采用的SA—Token 所以在该Demo 当中直接采取Sa-Token 方式 去授权和鉴权的服务
2 授权和鉴权服务设计 分为好几种方案
2.1 、全局鉴权中心
有些微服务项目弄了个全局的鉴权中心,所有微服务接收HTTP调用之后,先去全局鉴权中心验证用户的身份和权限,然后再允许用户调用微服务。
这种缺点 我个人认为 发送了多次http请求 其二 每个服务都与鉴权服务进行耦合 耦合度有点深,
二、BFF鉴权
BFF全称是Backends For Frontends,直译过来就是“服务于前端的后端”。 简而言之,BFF就是设计后端微服务API接口时,考虑到不同设备的需求,为不同的设备提供不同的API接口。
客户端不是直接访问服务器的公共接口,而是调用BFF层提供的接口,BFF层再调用基础的服务,不同的客户端拥有不同的BFF层,它们定制客户端需要的API接口。
有了BFF层之后,客户端只需要发起一次HTTP请求,BFF层就能调用不同的服务,然后把汇总后的数据返回给客户端,这样就减少了外网的HTTP请求,响应速度也就更快。
跨横切面(Cross-Cutting Concerns)的功能,需要协调更新框架升级发版(路由、认证、限流、安全),因此全部上沉,引入了 API Gateway,把业务集成度高的 BFF 层和通用功能服务层 API Gateway 进行了分层处理。
在新的架构中,网关承担了重要的角色,它是解耦拆分和后续升级迁移的利器。
在网关的配合下,单块 BFF 实现了解耦拆分,各业务线团队可以独立开发和交付各自的微服务,研发效率大大提升。
BFF的划分:
重要性
垂直业务,闭环
流量大小
另外,把跨横切面逻辑从 BFF 剥离到网关上去以后,BFF 的开发人员可以更加专注业务逻辑交付,实现了架构上的关注分离(Separation of Concerns)。
我们业务流量实际为:
移动端 -> API Gateway -> BFF -> Mircoservice
在 FE Web业务中,BFF 可以是 nodejs 来做服务端渲染(SSR,Server-Side Rendering),注意这里忽略了上游的 CDN、4/7层负载均衡(ELB)。
总结
基于服务器的身份认证
最为传统的做法 客服端存储cookie 一般是session id 服务器存储Session
Session 是每次用户认证通过以后 服务器需要创建一条记录保存用户信息 通常是在内存中 随着认证通过的用户越来越多 服务器的开销越来越大
在不同域名之前切换时 请求可能会被禁止 跨域问题
基于token方式身份认证
JWT 与Session 的差异相同点是 它们都是存储用户信息 然而Session 存在服务器端 而JWT 是在客户端
jwt 方式将用户状态分散到了客户端中 可以明显减轻服务端的内存压力
在不同域名之前切换时 请求可能会被禁止 跨域问题
基于token 与服务器身份认证
解析方式 jwt 使用算法直接解析得到用户信息 Session 需要额外的数据映射 实现匹配
jwt 只有过期时间的限制 session 保存在服务器 可控性强大
跨平台 jwt 就是一个string 可以任意传送 Session 跨平台需要一个统一解析方式
时效性 jwt一旦生成 独立存在 很难做特殊控制 Session 时效性可以由服务端控制
代码如下
用户登录鉴权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:用户服务,对外暴露用户操作相关接口,如新增用户等
搭建父项目工程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=用户登录鉴权JWT代码实现