目錄
一、什么是 JWT ?
二、什么時(shí)候使用 JWT ?
三、JWT 格式
1、Header
2、Payload
3、Signature
4、 JWT實(shí)現(xiàn):
官網(wǎng)
- 官網(wǎng)?JSON Web Tokens - jwt.io
- RFC 7519文檔?RFC 7519: JSON Web Token (JWT)
一、什么是 JWT ?
JSON Web Token(JWT)是一種開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊且自包含的方式,用于在各方之間作為JSON對(duì)象安全地傳輸信息。
JWT可以使用密碼(使用HMAC算法)或使用RSA或ECDSA的公鑰/私鑰對(duì)進(jìn)行簽名。
加簽后的token 能夠使用 JWT 里的算法驗(yàn)證 json 的完整性.
二、什么時(shí)候使用 JWT ?
- 授權(quán)
- 信息交換
- 使用方式:服務(wù)端根據(jù)規(guī)范生成一個(gè)令牌(token),并且發(fā)放給客戶端(保存在客戶端)。此時(shí)客戶端請(qǐng)求服務(wù)端的時(shí)候就可以攜帶者令牌,以令牌來證明自己的身份信息。
- 前端在每次請(qǐng)求時(shí)將JWT放入HTTP Header中的Authorization位。(解決XSS和XSRF問題)
JWT優(yōu)勢(shì)
? ? 簡潔:可以通過URL、POST參數(shù)或者在HTTP Header發(fā)送,因?yàn)閿?shù)據(jù)量小,傳輸速度也很快
? ? 自包含:負(fù)載中包含了所有用戶所需要的信息,避免了多次查詢數(shù)據(jù)庫
? ? 因?yàn)門oken是以JSON加密的形式保存在客戶端的,所以JWT是跨語言的,原則上任何web形式? ? ? ?都支持
? ? 不需要在服務(wù)端保存會(huì)話信息,特別適合用于分布式微服務(wù)。
? ? 更適合用于移動(dòng)端:當(dāng)客戶端是非瀏覽器平臺(tái)時(shí),cookie是不被支持的,此時(shí)使用token認(rèn)證方? ? ? ?式會(huì)簡單很多
? ? ?單點(diǎn)登錄友好:由于cookie無法跨域,難以實(shí)現(xiàn)單點(diǎn)登錄。但是,使用token進(jìn)行認(rèn)證的話,? ? ? ? ? ? token可以被保存在客戶端的任意位置的內(nèi)存中,不一定是cookie,所以不依賴cookie,不會(huì)? ? ? ? ? 存在這些問題
?
三、JWT 格式
使用逗號(hào)分隔的三部分 :
- Header
- Payload
- Signature
token 格式:xxxxx.yyyyy.zzzzz
1、Header
Header 通常由 token 類型和簽名算法名兩部分組成.是token的第1部分
例如:
{ |
|
"alg": "HS256", // 簽名算法 |
|
"typ": "JWT" // token類型 |
|
} |
然后, 這個(gè)JSON 使用 Base64Url 編碼后放到 JWT 的第1部分.
2、Payload
Payload 是token的第2部分.包含了一些聲明(claims).聲明的名字必須是唯一的.
claims 是包含了 用戶數(shù)據(jù)和其他數(shù)據(jù)的陳述,
有三種類型的聲明:
- Registered Claim Name
預(yù)定義好的一些聲明(如果有需要就使用,沒需要可不使用):
- "iss"
- "sub"
- "aud"
- "exp"
- "nbf"
- "iat"
- "jti"
更多參見?JSON Web Token (JWT)
-
Public Claim Names
公共的聲明,可以預(yù)先定義在?IANA JSON Web Token Registry?中,或者定義在1個(gè)能解決名字沖突的地方. -
Private Claim Names
雙方共享數(shù)據(jù)使用的私有名字.既不在 Registered Claim Name 也不在 Public Claim Names 中.
payload 示例
{ |
|
"sub": "1234567890", |
|
"name": "John Doe", |
|
"admin": true |
|
} |
JSON?
然后, 這個(gè)JSON 使用 Base64Url 編碼后放到 JWT 的第2部分.
3、Signature
拿到編碼后的 header 和 編碼后的 payload 使用 密碼進(jìn)行簽名.
使用 HMAC SHA256 加簽示例:
HMACSHA256( |
base64UrlEncode(header) + "." + |
base64UrlEncode(payload), |
secret) |
Signature需要使用編碼后的header和payload以及我們提供的一個(gè)秘鑰,然后使用header中指定的簽名算法進(jìn)行簽名,簽名的作用是保證JWT沒有被篡改過
HMACSHA256(base64UrlEncode(header)+“.”+base64UrlEncode(payload),secret)
實(shí)際上是對(duì)頭部信息和負(fù)載內(nèi)容進(jìn)行簽名,防止內(nèi)容被篡改,如果有人對(duì)頭部以及負(fù)載內(nèi)容解碼后進(jìn)行修改,再進(jìn)行編碼,最后加上之前的簽名組合形成新的JWT的話,那么服務(wù)器端會(huì)判斷出新的頭部和負(fù)載形成的簽名和JWT上附帶的簽名是不一樣的。如果要對(duì)新的頭部和負(fù)載進(jìn)行簽名,由于不知道服務(wù)器加密時(shí)使用的秘鑰,得出來的結(jié)果也是不一樣的
注意:secret是保存在服務(wù)器端的,jwt的簽發(fā)生成也是在服務(wù)器端的,secret就是用來進(jìn)行jwt的簽發(fā)和jwt的驗(yàn)證,所以,它就是你服務(wù)端的私鑰,在任何場(chǎng)景都不應(yīng)該流露出去。
4、 JWT實(shí)現(xiàn):
? 1、依賴引入
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt-jsonwebtoken.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>RELEASE</version>
</dependency>
2、生成Token?
// 簽名密鑰
private static final String SECRET = "!Doker$";
public String createToken(Map<String, Object> claims, String subject) {
final Date createdDate = clock.now();
final Date expirationDate = calculateExpirationDate(createdDate);
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(createdDate)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, Algorithm.HMAC256(SECRET))
.compact();
}
private Date calculateExpirationDate(Date createdDate) {
return new Date(createdDate.getTime() + expiration * 1000);
}
3、刷新Token?
public String RefreshToken(String token) {
final Date createdDate = clock.now();
final Date expirationDate = calculateExpirationDate(createdDate);
final Claims claims = getAllClaimsFromToken(token);
claims.setIssuedAt(createdDate);
claims.setExpiration(expirationDate);
return Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, Secret)
.compact();
}
4、token發(fā)送給前端
傳入當(dāng)前用戶的功能與用戶信息,登錄名生成token,寫入response的返回頭中,前端獲取后保存在前端的本地緩存中,后續(xù)前端請(qǐng)求要把token放在頭header里。文章來源:http://www.zghlxwxcb.cn/news/detail-738180.html
//登錄成功之后
List<Object> functs=(List<Object>) authResult.getAuthorities();
//當(dāng)前功能列表
String loginName=authResult.getName();//登錄名
Users obj=(Users)authResult.getPrincipal();//用戶信息
String token=JwtUtil.createToken(loginName,functs,obj);
//生成token TOKEN_HEADER= Authorization TOKEN_PREFIX=Bearer token值
response.setHeader(JwtUtil.TOKEN_HEADER,JwtUtil.TOKEN_PREFIX+token);
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK); //個(gè)人編寫的視圖對(duì)象
DTO dto=new DTO<>();
dto.setCode("000000");
dto.setMessage("認(rèn)證通過");
PrintWriter pw=response.getWriter();
pw.write(JsonUtil.set(dto));//寫入json
pw.flush();//強(qiáng)制刷新
pw.close();//關(guān)閉流
5、驗(yàn)證用戶請(qǐng)求攜帶token文章來源地址http://www.zghlxwxcb.cn/news/detail-738180.html
String header = request.getHeader(JwtUtil.TOKEN_HEADER);
if (null == header || !header.toLowerCase().startsWith(JwtUtil.TOKEN_PREFIX)) {
// 如果頭部 Authorization 未設(shè)置或者不是 basic 認(rèn)證頭部,則當(dāng)前
// 請(qǐng)求不是該過濾器關(guān)注的對(duì)象,直接放行,繼續(xù)filter chain 的執(zhí)行
chain.doFilter(request, response);
return;
}
try {
String token = header.replace(JwtUtil.TOKEN_PREFIX, "");
// 驗(yàn)證token是否過期
if (JwtUtil.isExpiration(token)) {
throw new javax.security.sasl.AuthenticationException("token 驗(yàn)證不通過");
}
//檢查token是否能解析
Users user = (Users) JwtUtil.getUser(token);
if (null == user) {
throw new javax.security.sasl.AuthenticationException("token 驗(yàn)證不通過");
}
//驗(yàn)證成功
到了這里,關(guān)于JWT(JSON Web Token )詳解及實(shí)例的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!