1. 程式人生 > >Token 的生成 和 驗證

Token 的生成 和 驗證

說明 本文 完全就是轉載被人的文章  其目的是為了自己做一下筆記 

補充: 發現一個不足之處,就是即便去除了隨機函式,每次生成的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