目录
一、JWT介绍
二、安装依赖
三、登陆接口
1、令牌工具类
2、接口代码
四、说明
一、JWT介绍
JWT全称:JSON Web Token (官网:JSON Web Tokens - jwt.io)
-
定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。
自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。
简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。
JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)
-
第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{"alg":"HS256","type":"JWT"}
-
第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{"id":"1","username":"Tom"}
-
第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。
JWT是如何将原始的JSON格式数据,转变为字符串的呢?
其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码
Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号
需要注意的是Base64是编码方式,而不是加密方式。
二、安装依赖
<!-- JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
三、登陆接口
1、令牌工具类
public class JwtUtils {
private static String signKey = "zqhjwt";//签名密钥
private static Long expire = 43200000L; //有效时间
/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)//自定义信息(有效载荷)
.signWith(SignatureAlgorithm.HS256, signKey)//签名算法(头部)
.setExpiration(new Date(System.currentTimeMillis() + expire))//过期时间
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)//指定签名密钥
.parseClaimsJws(jwt)//指定令牌Token
.getBody();
return claims;
}
}
2、接口代码
LoginController
@RestController
public class LoginController {
@Autowired
EmpService empService;
@PostMapping("login")
public Result login(@RequestBody Emp emp){
Emp e = empService.login(emp);
if(e!= null)
{
Map<String,Object> clzims = new HashMap<>();
clzims.put("id",e.getId());
clzims.put("name",e.getName());
clzims.put("username",e.getUsername());
// 生成jwt令牌
String jwt = JwtUtils.generateJwt(clzims);
return Result.success(jwt);
}
return Result.error("用户名或密码错误");
}
}
Service
@Override
public Emp login(Emp emp) {
Emp loginEmp = empMapper.getByUerAndPsw(emp);
return loginEmp;
}
mapper
@Select("SELECT * from emp where username = #{username} and password = #{password}")
Emp getByUerAndPsw(Emp emp);
四、说明
需求:
-
生成令牌
在登录成功之后来生成一个JWT令牌,并且把这个令牌直接返回给前端 -
校验令牌
拦截前端请求,从请求中获取到令牌,对令牌进行解析校验
步骤:
-
引入JWT工具类
在项目工程下创建uitle包,并把提供JWT工具类复制到该包下 -
登录完成后,调用工具类生成JWT令牌并返回
接口文档
-
响应数据
参数格式:application/json
参数说明:
名称 类型 是否必须 默认值 备注 其他信息 code number 必须 响应码, 1 成功 ; 0 失败 msg string 非必须 提示信息 data string 必须 返回的数据 , jwt令牌 响应数据样例:
{ "code": 1, "msg": "success", "data": "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo" }
-
备注说明
用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,都需要在请求头header中携带到服务端,请求头的名称为 token ,值为 登录时下发的JWT令牌。
如果检测到用户未登录,则会返回如下固定错误信息:
{ "code": 0, "msg": "NOT_LOGIN", "data": null }
解读完接口文档中的描述了,目前我们先来完成令牌的生成和令牌的下发,我们只需要生成一个令牌返回给前端就可以了。