# spring-jwt
**Repository Path**: heyuanmei/spring-jwt
## Basic Information
- **Project Name**: spring-jwt
- **Description**: spring boot 整合jwt
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2023-02-14
- **Last Updated**: 2023-05-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 1. 技术学习笔记
## 一. jwt: 鉴权框架
#### 简介
(json web token)轻量级的鉴权框架、无状态登录(有状态:信息存在服务器端(**session**),无状态:信息存在客户端(**cookie**))
好处是:不存储在服务端,减少服务端的压力。
> - 各方之间以JSON对象安全地传输信息。
>
> - 这些信息可以通过数字签名进行验证和信任。
>
> - 使用密匙(使用HMAC算法或使用RSA的公钥/私钥)对来对JWT进行签名。
#### JWT的认证流程

```consel
- 用户携带用户名和密码请求访问
- 服务器校验用户凭据
- 应用提供一个token给客户端
- 客户端存储token,并且在随后的每一次请求中都带着它
- 服务器校验token并返回数据
```
#### Token的结构
- 头部(Header)
- 载荷(playload)
- 签名(signature)
1. **Header**
token是什么类型,采用了何种加密算法;头部有两部分信息:令牌的类型(即JWT)和所使用的签名算法,例如HMAC SHA256或RSA。
```consel
{ "typ": "JWT", "alg": "HS256"}
```
2. **playload**
存放一些不敏感的用户信息,用来传递数据。官方提供的几个标准字段,同时也可以自己往里面加自定义的字段和内容。类似一个Map集合。jwt的标准定义包含五个字段:
- `iss`:该JWT的签发者
- `sub `: 该JWT所面向的用户
- `aud` : 接收该JWT的一方
- `exp(expires)` : 什么时候过期,这里是一个Unix时间戳
- `iat(issued at)`: 在什么时候签发的
3. **signature**
主要是将`header`和`payload`的`base64`编码后内容用**点拼接**在一起然后进行加密生成签名。
服务端需要利用这签名来校验token是否被篡改(验签),是JWT最后一个部分。
该部分是使用了header指定的算法(如:HS256)加密后的数据,包含三个部分:
- `header `(base64加密后的)
- `payload `(base64加密后的)
- `secret `私钥
```java
secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该泄露出去。
一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。
```
## 二. shiro

有状态访问的缺点:
1、服务器压力增大
通常session是存储在内存中的,每个用户通过认证之后都会将session数据保存在服务器的内存中,而当用户量增大时,服务器的压力增大。
2、CSRF跨站伪造请求攻击
session是基于cookie进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。
3、扩展性不强
如果将来搭建了多个服务器,虽然每个服务器都执行的是同样的业务逻辑,但是session数据是保存在内存中的(不是共享的),用户第一次访问的是服务器1,当用户再次请求时可能访问的是另外一台服务器2,服务器2获取不到session信息,就判定用户没有登陆过。
## 三. spring security 安全框架
#### 定义
- Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。
- Spring 是非常流行和成功的 Java 应用开发框架,SpringSecurity 正是 Spring 家族中的成员。SpringSecurity 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。
spring Security就是由多个过滤器组成的过滤器链,多个过滤器之间各司其职,都有各自的功能。
#### 核心功能
核心功能是用户认证(Authentication)和用户授权(Authorization)两个部分。
- 用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。
- 用户授权指的是验证某个用户是否有权限执行某个操作。
#### 原理
- 过滤器:
```consel
1.[org.springframework.security.web.context.SecurityContextPersistenceFilter]
此过滤器主要是在 SecurityContextRepository 中 保存或者更新 SecurityContext,并交给后续的过滤器操作。
而 SecurityContext 中保存了当前用户认证、权限等信息。
2.【org.springframework.security.web.csrf.CsrfFilter】
此过滤器用于防止 CSRF 攻击。Spring Security 4.0 开始,默认开启 CSRF 防护,针对 PUT、POST、DELETE 等请求进行防护。
注:
CSRF 指的是 Cross Site Request Forgery,即 跨站请求伪造。
简单理解为:用户登录一个网站 A,并打开了另一个网站 B,B 网站携带恶意代码 且使用用户身份去访问 网站 A。
3.【org.springframework.security.web.authentication.logout.LogoutFilter】
匹配 URL(默认为 /logout),用于实现用户退出并清除认证信息。
4.【org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter】
匹配 URL(默认为 /login),用于实现用户登录认证操作(必须为 POST 请求)。
5.【org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter】
若没有指定登录认证界面,此过滤器会提供一个默认的界面。
【org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter】
若没有指定登出界面,此过滤器会提供一个默认的界面。
6.【org.springframework.security.web.authentication.AnonymousAuthenticationFilter】
创建一个匿名身份,用于系统的访问。(兼容游客登录模式)
7.【org.springframework.security.web.access.ExceptionTranslationFilter】
位于整个 springSecurityFilterChain 过滤链后方,用于处理链路中的异常(跳转到指定页面或者返回错误信息)。
8.【org.springframework.security.web.access.intercept.FilterSecurityInterceptor】
获取资源访问的授权信息,根据 SecurityContext 中存储的用户信息来决定操作是否有权限。
```
#### 认证授权的决策流程
> 一个请求过来时通过各个过滤器,最后通过FilterSecurityInterceptor来判断这个请求url是否是不需要验证的,如果是就直接访问到我们的接口api。如果不是的话,再判断当前请求线程中是否有authentication的认证对象,如果有就放行,如果没有就返回登录页面(比如这里我们设置的是登录表单的方式),来到登录页面输入账号密码登录后就会来到 UsernamePasswordAuthenticationFilter,经过一系列的操作,最后验证成功就会把认证对象authentication放进securityContext中,然后FilterSecurityInterceptor判断到当前请求线程中这个认证对象就放行,返回的时候最后会通过securityContextpersistenceFilter,判断当前线程是否有securityContext,如果有就放进session,那么下次再请求这个url的时候会首先通过securityContextpersistenceFilter这个过滤器,判断session中是否有securityContextduxiiang,如果有就放进当前请求线程中,然后最后经过FilterSecurityInterceptor时再判断当前请求线程是否有认证对象,由于最前面经过securityContextpersistenceFilter,已经从session中把认证对象放进了当前请求线程中,所以FilterSecurityInterceptor会直接放行,这样就访问到我们的接口api。
## 四. mybatis-pluse
### 1. 优势
**强大的 CRUD 操作**:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求。
**支持 Lambda 形式调用**:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错。
**支持主键自动生成**:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题。
**支持 ActiveRecord 模式**:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
**支持自定义全局通用操作**:支持全局通用方法注入( Write once, use anywhere )。
**内置代码生成器**:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用。
**内置分页插件**:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询。
**分页插件支持多种数据库**:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库。
**内置性能分析插件**:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询。
**内置全局拦截插件**:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作。
### 2. Service 的CRUD接口
- ### Save
```java
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection entityList);
// 插入(批量)
boolean saveBatch(Collection entityList, int batchSize);
```
- ### SaveOrUpdate
```java
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection entityList, int batchSize);
```
- ### Remove
```java
// 根据 entity 条件,删除记录
boolean remove(Wrapper queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection extends Serializable> idList);
```
- ### Update
```java
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection entityList, int batchSize);
```
- ### Get
```java
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map getMap(Wrapper queryWrapper);
// 根据 Wrapper,查询一条记录
V getObj(Wrapper queryWrapper, Function super Object, V> mapper);
```
- ### List
```java
// 查询所有
List list();
// 查询列表
List list(Wrapper queryWrapper);
// 查询(根据ID 批量查询)
Collection listByIds(Collection extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection listByMap(Map columnMap);
// 查询所有列表
List