Token 的生成 和 驗證
阿新 • • 發佈:2018-11-06
說明 本文 完全就是轉載被人的文章 其目的是為了自己做一下筆記
補充: 發現一個不足之處,就是即便去除了隨機函式,每次生成的token都是不一樣的,這樣一來並不符合我們的預期
1. 加密工具類,XXTEAUtil
import org.apache.commons.codec.binary.Base64; public class XXTEAUtil { /** * 使用金鑰加密資料 * @param plain * @param key * @return */ public static byte[] encrypt(byte[] plain, byte[] key) { if (plain.length == 0) { return plain; } return toByteArray(encrypt(toIntArray(plain, true), toIntArray(key, false)), false); } /** * 使用金鑰解密 * @param cipher * @param key * @return */ public static byte[] decrypt(byte[] cipher, byte[] key) { if (cipher.length == 0) { return cipher; } return toByteArray(decrypt(toIntArray(cipher, false), toIntArray(key, false)), true); } /** * 使用金鑰加密資料 * @param v * @param k * @return */ public static int[] encrypt(int[] v, int[] k) { int n = v.length - 1; if (n < 1) { return v; } if (k.length < 4) { int[] key = new int[4]; System.arraycopy(k, 0, key, 0, k.length); k = key; } int z = v[n], y = v[0], delta = 0x9E3779B9, sum = 0, e; int p, q = 6 + 52 / (n + 1); while (q-- > 0) { sum = sum + delta; e = sum >>> 2 & 3; for (p = 0; p < n; p++) { y = v[p + 1]; z = v[p] += (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); } y = v[0]; z = v[n] += (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); } return v; } /** * 使用金鑰解密資料 * @param v * @param k * @return */ public static int[] decrypt(int[] v, int[] k) { int n = v.length - 1; if (n < 1) { return v; } if (k.length < 4) { int[] key = new int[4]; System.arraycopy(k, 0, key, 0, k.length); k = key; } int z = v[n], y = v[0], delta = 0x9E3779B9, sum, e; int p, q = 6 + 52 / (n + 1); sum = q * delta; while (sum != 0) { e = sum >>> 2 & 3; for (p = n; p > 0; p--) { z = v[p - 1]; y = v[p] -= (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); } z = v[n]; y = v[0] -= (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); sum = sum - delta; } return v; } /** * 位元組陣列轉換為整型陣列 * @param data * @param includeLength * @return */ private static int[] toIntArray(byte[] data, boolean includeLength) { int n = (((data.length & 3) == 0) ? (data.length >>> 2) : ((data.length >>> 2) + 1)); int[] result; if (includeLength) { result = new int[n + 1]; result[n] = data.length; } else { result = new int[n]; } n = data.length; for (int i = 0; i < n; i++) { result[i >>> 2] |= (0x000000ff & data[i]) << ((i & 3) << 3); } return result; } /** * 整型陣列轉換為位元組陣列 * @param data * @param includeLength * @return */ private static byte[] toByteArray(int[] data, boolean includeLength) { int n = data.length << 2; if (includeLength) { int m = data[data.length - 1]; if (m > n) { return null; } else { n = m; } } byte[] result = new byte[n]; for (int i = 0; i < n; i++) { result[i] = (byte) ((data[i >>> 2] >>> ((i & 3) << 3)) & 0xff); } return result; } /** * 先XXXTEA加密,後Base64加密 * @param plain * @param key * @return */ public static String encrypt(String plain, String key) { String cipher = ""; byte[] k = key.getBytes(); byte[] v = plain.getBytes(); cipher = new String(Base64.encodeBase64(XXTEAUtil.encrypt(v, k))); cipher = cipher.replace('+', '-'); cipher = cipher.replace('/', '_'); cipher = cipher.replace('=', '.'); return cipher; } /** * 先Base64解密,後XXXTEA解密 * @param cipher * @param key * @return */ public static String decrypt(String cipher, String key) { String plain = ""; cipher = cipher.replace('-', '+'); cipher = cipher.replace('_', '/'); cipher = cipher.replace('.', '='); byte[] k = key.getBytes(); byte[] v = Base64.decodeBase64(cipher); plain = new String(XXTEAUtil.decrypt(v, k)); return plain; } }
2 . token的生成和驗證
import java.util.Random; import java.util.concurrent.TimeUnit; import org.apache.commons.lang.StringUtils; public class TokenUtil { private static final String[] codeBase= {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}; private static Random rand= new Random(); /** XXTEA加密解密的金鑰 */ private static String secKey = "captcha"; /** token超時門限(天) */ private static long expire = 30; /** 驗證碼字元數 */ private static int charCount = 4; public static final String genToken() { StringBuffer sb= new StringBuffer(); for(int i=0; i<charCount; i++){ int randInt= Math.abs(rand.nextInt()); sb.append(codeBase[randInt % codeBase.length]); } long timestamp= System.currentTimeMillis(); String token= null; token= String.format("%s_%d", sb.toString(), timestamp); System.out.println("未加密的token:"+token); token= XXTEAUtil.encrypt(token, secKey); return token; } public static final boolean verificationToken(String token) throws StatusInfoException{ String plainText= XXTEAUtil.decrypt(token, secKey); if (StringUtils.isBlank(plainText)){ throw new IllegalStateException("解密失敗,token可能遭到篡改"); } String[] plainTextArr= plainText.split("_"); if (plainTextArr.length!=2){ throw new IllegalStateException("token資料格式錯誤"); } long timestamp= 0; try{ timestamp= Long.parseLong(plainTextArr[1]); }catch(NumberFormatException e){ throw new IllegalStateException("時間戳無效"); } if ((System.currentTimeMillis() - timestamp)>TimeUnit.MILLISECONDS.convert(expire+5, TimeUnit.DAYS)){ throw new IllegalStateException("token已過期"); } return true; } }
本文非原創 轉載自 Token的生成和驗證--Java