生成比較短的Token字符串

有的時候,咱們須要生成一些Token做爲標識:如認證後的標識符,資源的提取碼等。一個比較常見的算法是生成一個GUID來做爲Token,因爲GUID的隨機性和惟一性特色,做爲Token是一個很是可靠的選擇。算法

GUID是一個128bit的數組,爲了方便攜帶,每每須要把它表述爲字符串的形式。通常把它表述爲以下形式:{79FAF822-7194-4FE3-8C4F-1D99BE71BC9C}。這樣有一個弊病:太長了,那麼咱們如何把它弄短點呢?數組

去掉沒必要要的修飾符, dom

首先能夠經過去掉無心義的括號和減號來較少長度:ui

    var token = guid.ToString("N"); 編碼

這樣字符串就成爲:79faf82271944fe38c4f1d99be71bc9c。感受仍是蠻長的。spa

使用Base64編碼來表示 token

前面的表示方法中,是使用的16機制來表示的,若是使用Base64編碼的話,則能夠進一步壓縮字符串資源

    var token = Convert.ToBase64String(guid.ToByteArray()).TrimEnd('='); 字符串

這樣字符串就成爲:Ivj6eZRx40+MTx2ZvnG8nA。看起來稍微好一點了。string

換一種Token生成方式

在使用Base64方式的編碼後,Token字符串仍是有20多位,有的時候仍是嫌它長了。因爲GUID自己就有128bit,在要求有良好的可讀性的前提下,很難進一步改進了。那咱們如何產生更短的字符串呢?還有一種方式就是較少Token的長度,不用GUID,而採用必定長度的隨機數,例如64bit,再用Base64編碼表示:

    var rnd = new Random();
    var tokenData = new byte[8];
    rnd.NextBytes(tokenData);
    var token = Convert.ToBase64String(tokenData).TrimEnd('=');

因爲這裏只用了64bit,此時獲得的字符串爲Onh0h95n7nw的形式,長度要短一半。這樣就方便攜帶多了。可是這種方式是沒有惟一性保證的。不過用來做爲身份認證的方式仍是能夠的(如網盤的提取碼)。

更進一步

前面的算法中,長度和隨機性卻是有了,可是沒有惟一性。對於須要惟一性的場景,則須要改寫一下token的生成算法了,我在這裏給一個簡單的示例:

    class Token
    {
        static Random rnd = new Random();
        static int seed = 0;

        public static string Create()
        {
            var rndData = new byte[4];
            rnd.NextBytes(rndData);

            var seedValue = Interlocked.Add(ref seed, 1);
            var seedData = BitConverter.GetBytes(seedValue);

            var tokenData = rndData.Concat(seedData).OrderBy(_ => rnd.Next());
            return Convert.ToBase64String(tokenData.ToArray()).TrimEnd('=');
        }
    }

這裏個人算法很是簡單:

  1. token由兩部分組成,32位的隨機數+32位的序列
  2. 由序列保證惟一性,由隨機數保證隨機性。
  3. 組合後再進行一次shuffle。

固然,我這個算法也有必定的侷限性,如:

  1. Token只能在4G範圍內保證惟一
  2. Token只能在上下文中保證惟一
  3. Token不是徹底隨機的

要解決這幾個問題,實如今任什麼時候候,任何位置,任何狀況下產生的Token都具備惟一性和隨機性也是能作到的。可是,要知道的是,任何功能都是附有必定的代價的。這些條件每每帶來的代價就是Token長度增長——GUID就是知足這一系列條件的算法。軟件的世界沒有銀彈,咱們只要在必定範圍內找到能解決問題的方法便可。

相關文章
相關標籤/搜索