一、What is JWT?
Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519),该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
二、JWT的发展来源
当我们开发前后端分离项目时,要求我们对用户会话状态要进行一个无状态处理,那我们知道普通的web项目用于管理用户会话的往往是 session,用户每次用服务器认证成功后,服务器都会发送一个 sessionid 给用户,session 是保存在服务端的,服务器通过 session 分辨用户,进行权限认证等一系列操作。每次请求完后,都会在 响应头中返回 sessionid 给浏览器,浏览器会将 sessionid 存储在 cookie 中,以后的每次请求都会在请求头中带上这个 sessionid 信息,服务器就会根据这个 sessionid 作为索引获取到具体的 session。
那上面讲述的场景就会出现一个痛点,当我们前后端分离后,我们的前端项目和后端项目分开部署,甚至会用到 nginx 来代理转发,也就是说前后端分离在应用解耦后增加了部署的复杂性。通常用户一次请求就要转发多次。如果用 session 每次携带 sessionid 到服务器,服务器还要查询用户信息。同时如果用户很多。这些信息存储在服务器内存中,给服务器增加负担。还有就是 CSRF(跨站伪造请求攻击)攻击,session 是基于 cookie 进行用户识别的, cookie 如果被截获,用户就会很容易受到跨站请求伪造的攻击。还有就是 sessionid 就是一个特征值,表达的信息不够丰富。不容易扩展。而且如果你后端应用是多节点部署。那么就需要实现 session 共享机制。不方便集群应用。
三、JWT的应用场景
JWT 就是上述痛点的解决方案之一,客户端在请求服务端进行登录操作时,服务端验证用户的账号和密码,验证成功后生成 token 返回给客户端,之后浏览器的每一次操作都会在请求头中带上这个 token,服务器会验证该 token 信息,验证成功后才会返回资源给浏览器。
JWT 的开销非常小,可以轻松在不同的域名中传递,所以在单点登录(SSO)中用到比较广泛,信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。
四、jwt整合到springboot,导入security依赖
<!-- springboot集成security实现jwt-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
1.编写一个简单的controller进行测试,其中security框架会默认弹出一个登录页面,以及默认生成一个账户和密码可以进行登录测试
package com.eduction.website.controller;
import com.eduction.website.entity.TUser;
import com.eduction.website.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @BelongsProject: CourseEducationWebsite
* @BelongsPackage: com.eduction.website.controller
* @Author: Mr.zhang
* @CreateTime: 2023-03-03 10:29
*/
@Controller
@RequestMapping("user")
public class UserController {
@Autowired
private IUserService userService;
/**
* @description:用户登录
* @author: mr.zhang
* @date: 2023/3/3 16:44
* @param: [user]
* @return: com.eduction.website.entity.TUser
**/
@GetMapping("login")
public TUser login(@RequestBody TUser user){
/*TUser tUser = userService.getByNum(user.getUserNum());
if (tUser==null)
return
if (user.getUserNum())*/
return user;
}
}
上图是security默认生成密钥,用户名默认为:user
下图是security初始化登陆页面
登录以后就可以访问到controller代码,我这里出现500是我做的一个全局捕获异常,你们的访问路径可以根据resultfull风格选择不同的传参方式,然后在controller中返回String类型的一句话,便于测试
五、根据自己的需求修改默认security过滤器配置
1.登录
(1)认证首先需要修改UsernamePasswordAuthenticationFilter自定义登录接口,调用ProviderManager的方法进行认证,如果认证通过就生成jwt存入redis中.
(2)需要再修改InMemoryUserDetailsMananger就是自定义一个userDetailService判断登录用户密码是否与数据库一致。
2.校验
(1)定义jwt认证过滤器,获取token,然后解析token获取userid从redis中获取,存入SecurityContextHodedr
3.导入插件依赖
<!--redis驱动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--json转换工具fastjson2依赖-->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.19</version>
</dependency>
<!--JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>