参考文章 : https://www.bilibili.com/video/BV1i54y1m7cP?p=1
看了b站up 主编程不良人 的JWT的视频后做的笔记,若想看原视频,请点击上面的参考文章
官方说明:
JSON Web令牌(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于将信息作为JSON对象在各方之间安全地传输。可以对该信息进行验证和信任,因为它是数字签名的。jwt可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。
通俗的说:
JWT的全称是JSON Web Token,它是开源的,通过json的形式作为web应用中的令牌,可以安全的以json的形式传输数据。在传输过程中,可以完成数据的加密与签名等。
当访问的页面需要令牌时,若前端发送请求时没有携带令牌,或者令牌信息被篡改了,后端系统都不能通过验证令牌,所以就不会转发到访问的页面。比如说需要用户登录才能访问的页面,就需要携带令牌。
当系统A与系统B需要数据交换时,就可以用JWT来进行信息交换,以保证数据的安全,防止被篡改。因为系统每次都会检验令牌,校验不通过,系统就不使用该信息。
我们知道http协议是无状态的,即当链接建立完成后,就会断开,当需要记录一些状态时(比如登录状态),就会出现问题,因为是无状态的,他不能长期存储一些信息。因此当客户端需要访问一些需要登录成功后才能访问的页面,服务器就不能知道用户是否登录了,因此就出现了session机制。
有了session后,当我们登录后,服务器就会生成一个session,并保存到服务器内存中,然后再以cookie的形式将这个session发送给客户端,cookie的key是sessionid,value就是session的值,这样客户端就有了一个状态了,在之后客户端每次发送请求的时候,就可以在请求头的cookie中携带该session的信息以访问有保护的页面。
缺点:
优点:
JWT是由三段结构组成的,分别是标头(Header)、有效载荷(Payload)、签名(Signature)。这三段结构的json格式,然后再加密,就会得到JWT,因此JWT的格式如下:xxxx.yyyy.zzzz
标头由两部分组成:令牌的类型(默认为JWT) 和 JWT加密所使用的算法(如HMAC、SHA256、RSA),然后再使用 Base64 编码,构成JWT的第一部分。格式如下:
{
"alg":"HS256",
"typ":"JWT"
}
有效负载是存放用户数据的声明,然后再使用 Base64 编码,构成JWT的第二部分。因此,千万能存放用户的敏感信息,因为别人是能解码看到你的敏感信息。格式如下:
{
"id":"123",
"name":"Xavier",
"status":"yes"
}
签名是使用前面两个json信息的 Base64 编码,再加一个盐值,最后再使用Header中指定的算法进行加密。
签名目的:
防止信息被篡改。若有人对头部和负载的内容解码后再进行修改,再进行编码,最后再加上之前的签名组成新的JWT的话,那么服务器是无法识别该JWT的,因为篡改后的头部和负载的新签名与原来的签名是绝对不可能一样的。若对新头部和负载内容进行签名,在不知道服务器的 密钥(盐值)的情况下,是绝对得不服务器到能验证通过的值。
最终效果:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
.eyJ1X2lkIjoxMjMsImV4cCI6MTYyMDAyNDY3OCwidXNlcm5hbWUiOiJYYXZpZXIifQ
.4i3di0tXbRgRLpPIU9GRk3vBQf-13_yDZzxJl8O6CKQ
依赖:
<dependency>
<groupId>com.auth0groupId>
<artifactId>java-jwtartifactId>
<version>3.15.0version>
dependency>
简单使用:
public class JWTTest {
private String sing = "asd@!#987@#!#"; //盐值
/**
* 生成JWT
*/
@Test
public void contextLoads() {
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE, 7);
String token = JWT.create()
.withClaim("u_id", 123) //payload
.withClaim("username", "Xavier")
.withExpiresAt(instance.getTime()) //超时时间
.sign(Algorithm.HMAC256(sing)); //签名(加密)
System.out.println(token);
}
/**
* 验证JWT,并获取其信息
*/
@Test
public void verify(){
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(sing)).build();
DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1X2lkIjoxMjMsImV4cCI6MTYyMDYzMDA2NCwidXNlcm5hbWUiOiJYYXZpZXIifQ.zTIeb7yJb1cKk1o7qCRiozcPafOdE7oln7cuJQZHcMA");
Integer u_id = verify.getClaim("u_id").asInt();
String username = verify.getClaim("username").asString();
System.out.println(u_id);
System.out.println(username);
}
}
异常类型:
AlgorithmMismatchException 算法不匹配异常
SignatureVerificationException 签名不一致异常
TokenExpiredException 令牌过期异常
InvalidclaimEkception 失效的payload异常
JWT验证流程:
GitHub代码地址:https://github.com/Xavier-777/jwt