什么是Token?
什么是token/token如何使用_萧先生.的博客-CSDN博客_token用法
什么是JWT?
JSON Web Token,通过JSON形式作为web应用的令牌,用于在各方之间安全地将信息作为JSON对象传输。在数据传输过程中还可以完成数据加密、签名等相关处理。
使用场景:
第一种:授权(常用)
前端系统访问后端系统的时候,使用功能jwt传一个令牌,如果这个令牌是后端系统可以放行的令牌,就允许访问。如果不是可以放行的令牌,或者没有携带令牌,就不允许访问
第二种:信息交换
为什么使用JWT授权?
1、基于传统的Session认证
1)认证流程:
2)缺点:
①每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言,session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大
②用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应地限制了负载均衡的能力。这也意味着限制了应用的扩展能力。
③因为是基于cookie来进行用户识别的,cookie如果被截获,用户就会很容易受到跨站请求伪造的危机。
④在前后端分离的系统中,前端系统在调用后端系统的时候,中间可能会经过很多的代理,那么每一层都要携带sessionId,如果后端是集群部署,还要实现session共享。
2、基于JWT认证
1)JWT的认证流程
认证通过之后,会通过JWT生成一个令牌,这个令牌永久保存在本地(浏览器端),以后前端每次访问后端的时候,后端只需要对携带的JWT进行一个认证,如果令牌合法,就可以调用,如果不是合法令牌,就直接返回错误信息。
2)优势:
①简洁:可以通过url或者post参数或者在http header中发送,数据量小,传输速度快
②自包含:可以直接从payload中取出用户信息,不需要查询数据库
③因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持
④不需要在服务端中保存会话信息,特别适用于分布式微服务
JWT结构:
JWT组成:Header.Payload.Signature
1、标头(Header)
标头组成:①令牌类型(typ) ②签名算法
会使用Base64编码Header
注意:
Base64是一种编码,也就是说,它是可以被翻译回原来的样子的,它并不是一种加密过程
{
"alg":"HS256",
"typ":"JWT"
}
2、有效载荷(Payload)
有效负载,其中包含声明,也会使用Base64编码Payload。声明是有关实体(通常是用户)和其他数据的声明。
注意:不要在Payload里面放用户的敏感信息,比如密码。因为JWT可能被拦截,然后用Base64解码。
{
"sub":"1234567890",
"name":"zhangsan",
"admin":true
}
3、签名(Signature)
Signature需要使用编码后的header和payload以及我们提供的一个密钥,然后使用header中指定的签名算法(HS256)进行签名。前面的作用是保证JWT没有被篡改过
如:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload).secret);
签名目的:防止内容被篡改。
使用JWT:
1、导入依赖
com.auth0
java-jwt
3.19.2
2、生成token
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Calendar;
import java.util.HashMap;
public class Test {
public static void main(String[] args) {
HashMap map = new HashMap();
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND,1000);
String token = JWT.create()
.withHeader(map) //Header(可以不用设置,因为Header有默认值:{"alg":"HS256", "typ":"JWT" })
.withClaim("userId",2) //payload
.withClaim("username","张三") //payload
.withExpiresAt(instance.getTime()) //指定令牌过期时间
.sign(Algorithm.HMAC256("MiYao")); //Signature
System.out.println(token);
}
}
输出结果:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjEzMjQ1NjEsInVzZXJJZCI6MiwidXNlcm5hbWUiOiLlvKDkuIkifQ.m04WmTQTwVJpaRODMX8r-NxvwF_kJVP3mXo7ubX26Po
3、根据令牌和签名解析数据
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
public class Test2 {
public static void main(String[] args) {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjEzMjQ1NjEsInVzZXJJZCI6MiwidXNlcm5hbWUiOiLlvKDkuIkifQ.m04WmTQTwVJpaRODMX8r-NxvwF_kJVP3mXo7ubX26Po";
//创建验证对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("MiYao")).build();
DecodedJWT verify = jwtVerifier.verify(token);
System.out.println(verify.getClaim("userId"));
System.out.println(verify.getClaim("username"));
System.out.println(verify.getExpiresAt()); //过期时间
}
}
输出结果:
2
"张三"
Wed Aug 24 15:02:41 CST 2022
4、常见异常信息
SignatureVerificationException 签名不一致异常
TokenExpiredException 令牌过期异常
AlgorithmMismatchException 算法不匹配异常
InvalidClaimException 失效的payload异常