利用JWT生成Token
阿新 • • 發佈:2018-11-21
開篇
實現Token的方式有很多,本篇介紹的是利用Json Web Token(JWT)生成的Token.JWT生成的Token有什麼好處呢?
- 安全性比較高,加上密匙加密而且支援多種演算法。
- 攜帶的資訊是自定義的,而且可以做到驗證token是否過期。
- 驗證資訊可以由前端儲存,後端不需要為儲存token消耗記憶體。
本篇分3部分進行講解。
-
- 什麼是JWT
-
- JWT的程式碼實現,程式碼將JWT封裝成兩個工具類,可以直接呼叫。
-
- 總結
如果原理很難懂,沒關係。可以直接看JWT的程式碼實現。程式碼已經上傳github。已經對程式碼進行封裝成工具類。可以直接使用。
什麼是JWT
JSON Web Token 簡稱JWT。
一個JWT實際上就是一個字串,它由三部分組成,頭部
、載荷
與簽名
。
JWT生成的token是這樣的
eyJpc3MiOiJKb2huI.eyJpc3MiOiJ.Kb2huIFd1IEp
生成的token,是3段,用
.
連線。下面有解釋。
頭部
用於描述關於該JWT的最基本的資訊,例如其型別以及簽名所用的演算法等。這也可以被表示成一個JSON物件。
例如:
{
"typ": "JWT",
"alg": "HS256"
}
載荷
其實就是自定義的資料,一般儲存使用者Id,過期時間等資訊。也就是JWT的核心所在,因為這些資料就是使後端知道此token是哪個使用者已經登入的憑證。而且這些資料是存在token裡面的,由前端攜帶,所以後端幾乎不需要儲存任何資料。
例如:
{
"uid": "xxxxidid", //使用者id
"exp": "12121212" //過期時間
}
簽名
簽名其實就是:
1.頭部和載荷各自base64加密後用.連線起來
,然後就形成了xxx.xx的前兩段token。
2.最後一段token的形成是,前兩段加入一個密匙用HS256演算法或者其他演算法加密形成。
3. 所以token3段的形成就是在簽名處形成的。
程式碼實現
1.看程式碼前一定要知道JWT是由頭部
、載荷
與簽名
組成。
2.程式碼已上傳github,希望點個贊
3. 程式碼將JWT封裝成兩個工具類,可以直接呼叫。
需要下載的jar包
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>4.23</version>
</dependency>
生成token
/**
* 1.建立一個32-byte的密匙
*/
private static final byte[] secret = "geiwodiangasfdjsikolkjikolkijswe".getBytes();
//生成一個token
public static String creatToken(Map<String,Object> payloadMap) throws JOSEException {
//3.先建立一個頭部Header
/**
* JWSHeader引數:1.加密演算法法則,2.型別,3.。。。。。。。
* 一般只需要傳入加密演算法法則就可以。
* 這裡則採用HS256
*
* JWSAlgorithm類裡面有所有的加密演算法法則,直接呼叫。
*/
JWSHeader jwsHeader = new JWSHeader(JWSAlgorithm.HS256);
//建立一個載荷Payload
Payload payload = new Payload(new JSONObject(payloadMap));
//將頭部和載荷結合在一起
JWSObject jwsObject = new JWSObject(jwsHeader, payload);
//建立一個密匙
JWSSigner jwsSigner = new MACSigner(secret);
//簽名
jwsObject.sign(jwsSigner);
//生成token
return jwsObject.serialize();
}
驗證token
//解析一個token
public static Map<String,Object> valid(String token) throws ParseException, JOSEException {
// 解析token
JWSObject jwsObject = JWSObject.parse(token);
//獲取到載荷
Payload payload=jwsObject.getPayload();
//建立一個解鎖密匙
JWSVerifier jwsVerifier = new MACVerifier(secret);
Map<String, Object> resultMap = new HashMap<>();
//判斷token
if (jwsObject.verify(jwsVerifier)) {
resultMap.put("Result", 0);
//載荷的資料解析成json物件。
JSONObject jsonObject = payload.toJSONObject();
resultMap.put("data", jsonObject);
//判斷token是否過期
if (jsonObject.containsKey("exp")) {
Long expTime = Long.valueOf(jsonObject.get("exp").toString());
Long nowTime = new Date().getTime();
//判斷是否過期
if (nowTime > expTime) {
//已經過期
resultMap.clear();
resultMap.put("Result", 2);
}
}
}else {
resultMap.put("Result", 1);
}
return resultMap;
}
呼叫的業務邏輯
//生成token的業務邏輯
public static String TokenTest(String uid) {
//獲取生成token
Map<String, Object> map = new HashMap<>();
//建立載荷,這些資料根據業務,自己定義。
map.put("uid", uid);
//生成時間
map.put("sta", new Date().getTime());
//過期時間
map.put("exp", new Date().getTime()+6);
try {
String token = TokenUtils.creatToken(map);
System.out.println("token="+token);
return token;
} catch (JOSEException e) {
System.out.println("生成token失敗");
e.printStackTrace();
}
return null;
}
//處理解析的業務邏輯
public static void ValidToken(String token) {
//解析token
try {
if (token != null) {
Map<String, Object> validMap = TokenUtils.valid(token);
int i = (int) validMap.get("Result");
if (i == 0) {
System.out.println("token解析成功");
JSONObject jsonObject = (JSONObject) validMap.get("data");
System.out.println("uid是" + jsonObject.get("uid"));
System.out.println("sta是"+jsonObject.get("sta"));
System.out.println("exp是"+jsonObject.get("exp"));
} else if (i == 2) {
System.out.println("token已經過期");
}
}
} catch (ParseException e) {
e.printStackTrace();
} catch (JOSEException e) {
e.printStackTrace();
}
}
public static void main(String[] ages) {
//獲取token
String uid = "kkksuejrmf";
String token = TokenTest(uid);
//解析token
ValidToken(token);
}
總結
JWT 的實踐其實還是挺簡單。安全性也是得到了保證,後端只需要儲存著密匙,其他資料可以儲存在token,由前端攜帶,這樣可以減低後端的記憶體消耗。
雖然token是加密的,但是攜帶的驗證資料還是不要是敏感資料.