1. 常用的認證機制
A. Cookie-Sesion
cookie-session認證機制是為一次請求認證在服務端創建一個session對象,同時在客戶端的瀏覽器創建一個cookie對象,通過客戶端帶上來的cookie對象與服務端的session對象匹配來實現狀態管理的。
基於session認證缺點:每個用戶經過我們的應用認證之后,都會在服務端做一次記錄,以方便用戶下次請求的鑒別,一般session都是保存在內存中,而隨着認證用戶的增多,服務端開銷會明顯增大;
如果認證信息(session)是被保存在內存中,這意味着用戶下次請求還必須要發到這台服務器上,這樣才能拿到授權的資源,對於分布式應用,則限制了負載均衡器的能力,不易擴展;
通過cookie來進行用戶識別,如果cookie被捕獲,服務器就會很容易受到跨站請求偽造的攻擊(CSRF)。
B. JWT token
JWT(Json Web Token)是為了在網絡應用環境間傳遞聲明而執行的一種基於JSON標准,JWT的聲明一般被用在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便與從資源服務器獲取資源,也可以增加一些額外的其他業務邏輯所必須的聲明信息。服務器不會保存任何會話狀態,即服務器無狀態。
特點:體積小,因而傳輸速度快
傳輸方式多樣,如URL/POST參數/HTTP頭部等方式傳輸
嚴格的結構化,在payload中包含了所有與用戶相關的驗證消息,如用戶可訪問路由、訪問有效期等信息,服務器無需再去連接數據庫驗證信息的有效性,並且payload支持為應用定制化
支持跨域驗證,特別適用於分布式站點單點登錄
由於服務器不保存會話狀態,所以使用期間不可能取消令牌或更改令牌權限,也就是一旦JWT簽發,在有效期內將會一直有效
2. maven依賴
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
3. JWT 結構
A. Header 頭部
{
"alg": "HS256", ——加密的算法,通常直接使用HMAC SHA256
"typ": "JWT" ——聲明類型,這里是JWT
}
B. Payload 載荷
載荷就是存放有效信息的地方,包含標准中注冊的聲明、公共的聲明和私有的聲明三部分
標准中注冊的聲明:
{
"iss": JWT簽發者
"sub": JWT所面向的用戶
"aud": 接收JWT的一方
"exp": JWT的過期時間
"nbf": 定義在什么時間之前,該JWT都是不可用
"iat": JWT簽發時間
"jti": JWT唯一身份標識,主要用作一次性token,避免重放攻擊
}
公共的聲明:一般添加用戶的相關信息或其他業務需要的必要信息,不要添加敏感信息,因為base64是對稱加密,可解密的
私有的聲明:是提供者與消費者所共同定義的聲明,也不要添加敏感信息
C .Signature 簽名
簽名是由base64后的header、base64后的payload加上秘鑰secret進行算法加密構成的
簽名的作用:簽名實際上是對頭部和載荷內容進行簽名,如果有人對頭部以及載荷的內容解碼之后進行修改,再編碼的話,加上未知的私鑰,那么新的簽名和之前的就不一樣,這樣能保證token不被篡改。
token就是將這三部分用符號點連接形成的,如:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NzgwMjc4ODksInVzZXJuYW1lIjoiYWRtaW4ifQ.uE-Nhr1C_gXVxYUdWik9T6_rIY9KLDYePddXbfvXNFs
4. JWT用法
A. 前端:Authorization: Bearer token 客戶端接收服務器返回的token,可存儲在localStorage中,每次客戶端與服務器交互都需要攜帶;
B. 后端:用戶請求登錄服務器 ->服務器接收到請求生成jwt token並返回 ->用戶請求攜帶token認證 ->認證通過接着后面的請求,認證不通過,前端重置登錄頁面
package com.ruhuanxingyun.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ruhaunxingyun.commons.CommonConstant;
import java.io.UnsupportedEncodingException;
import java.util.Date;
/**
* @description: JWT工具類
* @author: ruphie
* @date: Create in 2019/12/20 17:29
* @company: ruhuanxingyun
*/
public class JwtUtils {
private final static String USERNAME = "username";
/**
* 生成token
*
* @param secret 密鑰
* @param username 用戶名
* @return token
*/
public static String sign(String secret, String username) throws UnsupportedEncodingException {
Date date = new Date(System.currentTimeMillis() + CommonConstant.EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
String token = JWT.create()
.withClaim(USERNAME, username)
.withExpiresAt(date)
.sign(algorithm);
return token;
}
/**
* 根據token獲取用戶名
*
* @param token 令牌
* @return username
*/
public static String getUsername(String token) {
DecodedJWT decodedJWT = JWT.decode(token);
String username = decodedJWT.getClaim(USERNAME).asString();
return username;
}
/**
* 校驗token
*
* @param secret 密鑰
* @param username 用戶名
* @param token token
* @return 是否合法
*/
public static boolean verify(String secret, String username, String token) {
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWT.require(algorithm)
.withClaim(USERNAME, username)
.build()
.verify(token);
return true;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return false;
}
}
可參考:幾種常用的認證機制
Cookie/Session/Token/Session的詳解