1. 程式人生 > >Token生成規則以及工具

Token生成規則以及工具

Token工具
package com.frank.common.utils;

import com.alibaba.fastjson.JSON;
import com.frank.common.entity.TokenHeader;
import com.frank.common.entity.TokenPlayload;
import com.frank.common.entity.User;

import java.rmi.server.UID;
import java.util.UUID;

/**
 * Description:Token生成工具
 * 第一部分我們稱它為頭部(header),第二部分我們稱其為載荷(payload, 類似於飛機上承載的物品),第三部分是簽證(signature).
 * Auth: Frank
 * Date: 2017-11-02
 * Time: 下午 5:05
 */
public class TokenUtil { public static final String TOKEN_AES_KEY = "xiangli8Token"; public static final String REFREH_TOKEN_AES_KEY = "xiangli8RefreshToken"; public static final String JWT_TYP = "JWT"; public static final String JWT_ALG = "AES"; public static final String JWT_EXP = "30"
; public static final String JWT_ISS = "xiangli8"; /** * 獲得token * @param data 自定義資料 * @param <T> 自定義資料 * @return * @throws Exception */ public static <T> String getToken(T data) throws Exception { TokenPlayload<T> userTokenPlayload = new
TokenPlayload<>(); userTokenPlayload.setExpData(data); String jwt = createJWT(userTokenPlayload); return jwt; } /** * 生成jwt的header部分內容 * @return * @throws Exception */ private static String tokenHeaderBase64() throws Exception { TokenHeader tokenHeader = new TokenHeader(); tokenHeader.setTyp(JWT_TYP); tokenHeader.setAlg(JWT_ALG); String headerJson = JSON.toJSONString(tokenHeader); String headerBase64 = Base64Util.encryptBASE64(headerJson.getBytes()); return headerBase64; } /** * 生成jwt的payload部分內容 * @param tokenPlayload * @param <T>自定義的資料塊 * @return * @throws Exception */ private static <T> String tokenPayloadBase64(TokenPlayload<T> tokenPlayload) throws Exception { tokenPlayload.setIss(JWT_ISS); tokenPlayload.setExp(JWT_EXP); tokenPlayload.setIat(String.valueOf(System.currentTimeMillis())); String headerJson =JSON.toJSONString(tokenPlayload); String headerBase64 = Base64Util.encryptBASE64(headerJson.getBytes()); return headerBase64; } /** * 生成JWT * @return */ public static <T> String createJWT(TokenPlayload<T> tokenPlayload) throws Exception { StringBuilder jwtSb = new StringBuilder(); StringBuilder headerPlayloadSb = new StringBuilder(); String tokenHeaderBase64 = tokenHeaderBase64(); String tokenPayloadBase64 = tokenPayloadBase64(tokenPlayload); jwtSb.append(tokenHeaderBase64); jwtSb.append("."); jwtSb.append(tokenPayloadBase64); jwtSb.append("."); headerPlayloadSb.append(tokenHeaderBase64); headerPlayloadSb.append(tokenPayloadBase64); String headerPlayloadSalt = SaltUtil.addSalt(headerPlayloadSb.toString()); String key = AesUtil.initKey(TOKEN_AES_KEY+tokenPlayload.getIat()); String signature = Base64Util.encryptBASE64(AesUtil.encrypt(headerPlayloadSalt.getBytes(),key)); jwtSb.append(signature); return Base64Util.encryptBASE64(jwtSb.toString().getBytes()); } /** * 校驗token是否是伺服器生成的,以防token被修改 * @param jwtBase64 * @return * @throws Exception */ public static <T> boolean verifyJWT(String jwtBase64) throws Exception { String jwt = new String (Base64Util.decryptBASE64(jwtBase64)); if(!jwt.contains(".")){ return false; } String[] jwts = jwt.split("\\."); if(jwts.length<3){ return false; } TokenPlayload tTokenPlayload = JSON.parseObject(new String(Base64Util.decryptBASE64(jwts[1])),TokenPlayload.class); String key = AesUtil.initKey(TOKEN_AES_KEY+tTokenPlayload.getIat()); //解析出header跟playload StringBuilder headerPlayloadSb = new StringBuilder(); headerPlayloadSb.append(jwts[0]); headerPlayloadSb.append(jwts[1]); //解析signature String headerPlayloadSalt = new String (AesUtil.decrypt(Base64Util.decryptBASE64(jwts[2]),key)); return SaltUtil.verifyPwd(headerPlayloadSb.toString(),headerPlayloadSalt); } public static void main(String[] args) throws Exception { String jwt = getToken(new User(1L,"你是逗逼")); System.out.println("jwt:"+jwt); System.out.println("verifyJWT:"+verifyJWT(jwt)); } }
使用說明

1,根據上面生成一個由base64編碼的token,該token由Header,Payload,Signature組成。

2,token作為使用者請求的標識,客戶端儲存這token的全部資訊。服務端只需要儲存token的Signature部分。

3,服務端把token的Signature存於redis和伺服器的資料庫中。

4,客戶端請求的資料附帶token,服務端拿到token,首先校驗token,以防token偽造。校驗規則如下:

4.1,拆分出token的Header,Payload,Signature。
4.2,校驗Signature,通過token的header和payload生成Signature,看看生成的Signature是否和客戶端附帶上來的Signature一致。如果一致繼續請求操作,不一致則打回操作
4.3,檢視Signature是否存在伺服器的redis和資料庫中。如果不存在則打回請求操作

注意:上面涉及的加鹽演算法和Aes加密請看本人寫的其他文章