標籤:style blog http color 使用 os
產生比較短的Token字串
有的時候,我們需要產生一些Token作為標識:如認證後的標識符,資源的提取碼等。一個比較常見的演算法是產生一個GUID來作為Token,由於GUID的隨機性和唯一性特點,作為Token是一個非常可靠的選擇。
GUID是一個128bit的數組,為了方便攜帶,往往需要把它表述為字串的形式。一般把它表述為如下形式:{79FAF822-7194-4FE3-8C4F-1D99BE71BC9C}。這樣有一個弊病:太長了,那麼我們如何把它弄短點呢?
去掉不必要的修飾符,
首先可以通過去掉無意義的括弧和減號來較少長度:
var token = guid.ToString("N");
這樣字串就成為:79faf82271944fe38c4f1d99be71bc9c。感覺還是蠻長的。
使用Base64編碼來表示
前面的表示方法中,是使用的16機制來表示的,如果使用Base64編碼的話,則可以進一步壓縮字串
var token = Convert.ToBase64String(guid.ToByteArray()).TrimEnd(‘=‘);
這樣字串就成為:Ivj6eZRx40+MTx2ZvnG8nA。看起來稍微好一點了。
換一種Token產生方式
在使用Base64方式的編碼後,Token字串還是有20多位,有的時候還是嫌它長了。由於GUID本身就有128bit,在要求有良好的可讀 性的前提下,很難進一步改進了。那我們如何產生更短的字串呢?還有一種方式就是較少Token的長度,不用GUID,而採用一定長度的隨機數,例如 64bit,再用Base64編碼錶示:
var rnd = new Random();
var tokenData = newbyte[8];
rnd.NextBytes(tokenData);
var token = Convert.ToBase64String(tokenData).TrimEnd(‘=‘);
由於這裡只用了64bit,此時得到的字串為Onh0h95n7nw的形式,長度要短一半。這樣就方便攜帶多了。但是這種方式是沒有唯一性保證的。不過用來作為身份認證的方式還是可以的(如網盤的提取碼)。
更進一步
前面的演算法中,長度和隨機性倒是有了,但是沒有唯一性。對於需要唯一性的情境,則需要改寫一下token的產生演算法了,我在這裡給一個簡單的樣本:
classToken
{
staticRandom rnd = newRandom();
staticint seed = 0;
publicstaticstring Create()
{
var rndData = newbyte[4];
rnd.NextBytes(rndData);
var seedValue = Interlocked.Add(ref seed, 1);
var seedData = BitConverter.GetBytes(seedValue);
var tokenData = rndData.Concat(seedData).OrderBy(_ => rnd.Next());
returnConvert.ToBase64String(tokenData.ToArray()).TrimEnd(‘=‘);
}
}
這裡我的演算法非常簡單:
- token由兩部分組成,32位的隨機數+32位的序列
- 由序列保證唯一性,由隨機數保證隨機性。
- 組合後再進行一次shuffle。
當然,我這個演算法也有一定的局限性,如:
- Token只能在4G範圍內保證唯一
- Token只能在上下文中保證唯一
- Token不是完全隨機的
要解決這幾個問題,實現在任何時候,任何位置,任何情況下產生的Token都具有唯一性和隨機性也是能做到的。但是,要知道的是,任何功能都是附有一定的代價的。這些條件往往帶來的代價就是Token長度增加——GUID就是滿足這一系列條件的演算法。軟體的世界沒有銀彈,我們只要在一定範圍內找到能解決問題的方法即可。
System.Guid guid = System.Guid.NewGuid(); //Guid 類型 string strGUID = System.Guid.NewGuid().ToString(); //直接返回字串類型