JWT简介
在传统的有状态服务应用中,服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如Tomcat中的Session。
例如登录:用户登录后,我们把用户的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session,然后下次请求,用户携带cookie值来(这一步有浏览器自动完成),我们就能识别到对应session,从而找到用户的信息。这种方式目前来看最方便,但在分布式应用中,由服务端保存用户状态不是一种很好的选择(服务器集群高并发),因此JWT诞生
什么是JWT
JWT(JSON WEB Token)是一个标准:
借助JSON格式数据作为WEB应用请求中的令牌,进行数据的自包含设计,实现各方安全的信息传输,在数据传输过程中还可以对数据进行加密,签名等相关处理。同时JWT也是目前最流行的跨域身份验证解决方案(其官方网址为:https://jwt.io/)。可以非常方便的在分布式系统中实现用户身份认证。
JWT加密后数据结构分析
JWT加密后数据通常由三部分构成,分别为Header(头部),Payload(负载),Signature(签名),对应其格式如下:
eyJhbGciOiJIUzI1NiJ9.eyJwZXJtaXNzaW9ucyI6InN5czpyZXM6Y3JlYXRlLHN5czpyZXM6cmV0cmlldmUiLCJleHAiOjE2MjY5MzIyNTksImlhdCI6MTYyNjkzMDQ1OSwidXNlcm5hbWUiOiJqYWNrIn0.SQrRS5nuID1Xv5GMvUgnr7xrVzB7GcRFrkNak-x16Mw
Header(头部)
Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。
{
"alg": "HS256",
"typ": "JWT"
}
alg属性表示: 签名的算法(algorithm),默认是 HMAC SHA256(简写HS256);
typ属性表示: 这个令牌(token:加密后的数据)的类型(type),JWT 令牌统一写为JWT(该属性自定义数据的类型)
最后,将这个 JSON 对象使用Base64URL 算法转成字符串
Payload负载
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT规范中规定了7个官方字段,供选用:
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
其中重要的也就是 过期时间,剩下除了官方字段,还可以在这个部分定义私有字段,例如:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
注意:JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。这个 JSON 对象也要使用 Base64URL 算法转成字符串。
小总结
Header(头部) 和 Payload(负载)都是由Base64URL 编码进行二进制到文本字符串的编码
注意:它不是加密,只是二进制进行编码成字符串的形式
Signature(签名)
Signature 部分是对前两部分的签名,其目的是防止数据被篡改,需要以下两步:
1.需要指定一个密钥(secret)也就是盐。这个密钥只有服务器才知道,不能泄露给用户。
2.使用Header里面指定的签名算法(默认是HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(
base64UrlEncode(header) + "." + 加密盐
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户
JAVA实现JWT技术
1. 支持JWT的依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2. 实现代码:基于用户信息创建token信息
创建一个包含,三部分信息:头信息/负载信息/签名信息
//基于负载和算法创建token信息
public class JwtUtils {
//创建一个加密的秘钥,解密时需要使用
private static String secret = "au12df1fs115f85811s4fd";
//@param map 里面存储的是用户的信息
//@return String Jwt创建的字符串加密信息(用于传给用户)
public static String generatorToken(Map<String, Object> map) {
return Jwts.builder()//用于获取JWT的JwtBuilder对象
.setSubject("token")//设置主体对象(系统的主体名称,可以不写)
.setClaims(map)//负载信息(存储登录用户信息,敏感信息不可以存放,比如密码)
.setExpiration(new Date(System.currentTimeMillis() + (1000*60)))//该数据失效的时间
.setIssuedAt(new Date())//签发(签名生成发放用户)时间
.signWith(SignatureAlgorithm.HS256, secret)//签名加密算法,以及秘钥盐
.getExpiration()//获取令牌到期时间
.compact();//生成令牌
}
}
3. 实现解析JWT技术生成令牌
public class JwtTests {
//需要解密的秘钥,必须和加密时的秘钥相同
private static String secret = "au12df1fs115f85811s4fd";
public static Claims getClaimsFromToken(String token) {
return Jwts.parser()//取一个解析器对象
.setSigningKey(secret)//设置解析时使用的秘钥 secret为加密时的秘钥
.parseClaimsJws(token)//通过JWT加密生成的token获取token的负载信息
.getBody();//拿到负载信息
}
}
注意:当失效时间到期,在去解析则解析时会抛出JWT失效异常
JWT知识点集合
JWT 诞生的背景?
分布式架构应用平台下无状态会话时,规范令牌(通票)数据格式
JWT 是什么?
一种规范用户的令牌或者通票的数据格式,
JWT 规范定义的数据格式?
头,负载-详细内容,签名,思考一篇文章的构成
JWT 规范下JAVA相关API的应用?
jjwt依赖-Jwts
基于JWT规范下JAVA API 创建令牌,解析令牌
JWT规范中的数据格式有几部分构成?
3部分,前两部分会进行Base64编码,最会基于签名算法加密
令牌对象一般是在哪里创建?
服务端,可以创建令牌以后,响应到客户端
JWT令牌假如要存储在客户端你会存储在哪里?
Cookie,localStorage,sessionStorage
JWT令牌以怎样的方式从客户端传递到服务端?
请求参数,请求头