概述
本文為 .NET 開發者們分享一款輕量級開源的將數字編碼成字串的加密(短 ID 產生)工具類別庫—Hashids.net。
無論在前端還是後端的程式開發中,都會遇到讓系統自動產生一些編碼或 ID 的場景,並且要求產生的編碼或 ID 是不重複的(重複率極低的)。
前端開發中,常用的有 nanoid。而後端開發中,常用的技術則有:自增 ID、雪花 ID、GUID 等。其中,自增 ID 在中小型系統中使用比較常見,它佔用的儲存空間相對較小,檢索速度相對較快,但它不適用於分散式系統的建置;而雪花 ID 和 GUID 等佔用位元組較多,佔用儲存空間較大,檢索速度相對較慢,但後兩者適用於分散式系統的建置。
另外,還有一些場景,為了隱藏後端的真實 ID,在顯示到客戶端時,對真實 ID 進行加密處理,將真實的數字加密產生一個短字串,例如國外知名影片網站油管的影片位址類似 https://www.yt.com/watch?v=yVd7vbeFj-g,其中的參數 v 的值 yVd7vbeFj-g 即為一個加密的字串。
在 .NET、.NET Core、.NET 5\6\7\8 等程式開發中,如果你也想產生類似的加密字串,本文為 .NET 開發者們推薦 Hashids.net 這個開源的短 ID 產生(加密)類別庫。
Hashids.net 功能和特性
Hashids.net 可以將數字轉換成字串,例如將 347 轉換成 yr8,或將數字陣列 [27, 986] 轉換成 3kTMd。當然,你也可以將轉換後的字串再次轉換成數字或數字陣列。這在將多個參數捆綁成一個參數、隱藏實際 ID 或簡單地將它們用作短字串 ID 時非常有用。
Hashids.net 主要有如下的特性:
- 將整數轉換成唯一的短 ID(僅支援包含零在內的正整數)
- 為自增 ID 產生不可推測的非連續 id
- 支援單個數字或數字陣列
- 允許自訂字母和鹽
- 允許指定最小雜湊長度
Hashids.net 的安裝
Hashid.net 以 NuGet 套件發布,所以有如下的安裝方式:
1.NuGet 指令行
Install-Package Hashids.net
2.NuGet 套件管理工具
在專案中右鍵按一下相依項,如圖:

然後,在開啟的 NuGet 套件管理介面輸入關鍵字 Hashids.net,在搜尋到的結果中選中 Hashids.net 類別庫元件並安裝,如圖:

Hashids.net 的使用
匯入 Hashids.net 的命名空間
using HashidsNet;
編碼單個數字
實例化 Hashids 物件時,你可以傳遞一個唯一的鹽值,這樣你的雜湊值就不同於其他人的雜湊值。這裡使用 this is my salt 作為例子。
var Hashids = new Hashids("this is my salt");
var hash = hashids.Encode(12345);
執行結果為:NkK9
如果要轉換一個 Int64 類型的數字,則需要呼叫 EncodeLong() 方法,如下:
var hashids = new Hashids("this is my salt");
var hash = hashids.EncodeLong(666555444333222L);
執行結果為:KVO9yy1oO5j
解碼
Hashids.net 提供了將已編碼的字串反解碼的功能,但解碼時需使用與編碼相同的鹽值:
var hashids = new Hashids("this is my salt");
numbers = hashids.Decode("NkK9");
執行結果為:[ 12345 ]
var hashids = new Hashids("this is my salt");
numbers = hashids.DecodeLong("KVO9yy1oO5j");
執行結果為:[ 666555444333222L ]
使用不同的鹽值解碼
如果解碼時的鹽值與編碼時不相同,則解碼將失敗:
var hashids = new Hashids("this is my pepper");
numbers = hashids.Decode("NkK9");
執行結果為:[]
編碼多個數字
var hashids = new Hashids("this is my salt");
var hash = hashids.Encode(683, 94108, 123, 5);
執行結果為:aBMswoO2UB3Sj
多個數字編碼後的解碼
var hashids = new Hashids("this is my salt");
var numbers = hashids.Decode("aBMswoO2UB3Sj")
執行結果為:[ 683, 94108, 123, 5 ]
指定編碼後的最小雜湊長度
以下範例將對整數 1 進行編碼,並將最小雜湊長度設定為 8(預設情況下是 0——這表示雜湊將是可能的最短長度)。
var hashids = new Hashids("this is my salt", 8);
var hash = hashids.Encode(1);
執行結果為:gB0NV05e
解碼
var hashids = new Hashids("this is my salt", 8);
var numbers = hashids.Decode("gB0NV05e");
執行結果為:[ 1 ]
自訂雜湊字母
以下範例指定了自訂的雜湊字母為 abcdefghijkABCDEFGHIJK12345:
var hashids = new Hashids("this is my salt", 0, "abcdefghijkABCDEFGHIJK12345")
var hash = hashids.Encode(1, 2, 3, 4, 5)
執行結果為:Ec4iEHeF3
Hashids.net 的隨機性
Hashids.net 的主要目的是混淆 ID,此外,它還可以讓有規律的數字變得不可猜測和不可預測。
編碼重複的數字
var hashids = new Hashids("this is my salt");
var hash = hashids.Encode(5, 5, 5, 5);
編碼後,你不會看到任何重複的模式來表明雜湊中有 4 個相同的數字,執行結果為:1Wc8cwcE。
編碼有序的數字
var hashids = new Hashids("this is my salt");
var hash = hashids.Encode(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
執行結果為:kRHnurhptKcjIDTWC3sx
編碼自增的數字
var hashids = new Hashids("this is my salt");
hashids.Encode(1); // => NV
hashids.Encode(2); // => 6m
hashids.Encode(3); // => yD
hashids.Encode(4); // => 2l
hashids.Encode(5); // => rD
編碼十六進位
var hashids = new Hashids("this is my salt");
var hash = hashids.EncodeHex("DEADBEEF");
執行結果為:kRNrpKlJ
解碼十六進位
var hashids = new Hashids("this is my salt");
var hex = hashids.DecodeHex("kRNrpKlJ");
執行結果為:DEADBEEF
將字串加密產生短字串怎樣?
以下為站長擴充長字串轉短字串方法介紹
其實很簡單,將需要加密的原字串作為鹽,加密數字固定,這樣就簡單實現了:
public static string GetHashids(this string sourceStr, int number = 9)
{
var hashids = new Hashids(sourceStr);
return hashids.Encode(number);
}
單元測試如下:例如將本文別名【Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet】加密
[TestClass]
public class HashHelperUnitTest
{
[TestMethod]
public void Hashids_Success()
{
var blogPostSlugStr = "Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet";
var encodeStr1 = blogPostSlugStr.GetHashids();
var encodeStr2 = blogPostSlugStr.GetHashids();
Assert.AreEqual(encodeStr1, encodeStr2);
}
}
別名加密後為:【6Q】,可打開瀏覽器訪問本文短連結位址嘗試:https://dotnet9.com/6Q 。
註:這樣使用不是本庫的初衷,但將長字串轉成短字串這確不失為一種好想法,哈哈,記住這不可逆哈。
小知識
將一個長字串轉成短字串有多種方法可實現,常規做法:
- 使用資料庫儲存短字串和原字串,短字串可自行定義規則,例如從 1 開始取值,每次取值時讀資料庫,根據短字串取長字串或根據長字串取短字串。
優點:短字串與原字串一一對應,可以實現雙向轉換,不會出現重複的短字串。
缺點:需要頻繁讀寫資料庫,對資料庫的效能有一定的影響。
- 將長字串使用一種演算法轉成短字串,有演算法是可逆的,有的是不可逆的。
無需資料庫儲存,但長度可能會略長。
- 可逆演算法範例(C#):
public static string ShortenString(string longString)
{
byte[] bytes = Encoding.UTF8.GetBytes(longString);
string shortString = Convert.ToBase64String(bytes);
return shortString;
}
public static string RestoreString(string shortString)
{
byte[] bytes = Convert.FromBase64String(shortString);
string longString = Encoding.UTF8.GetString(bytes);
return longString;
}
- 不可逆演算法範例(C#):
public static string ShortenString(string longString)
{
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(longString));
string shortString = Convert.ToBase64String(hashBytes);
return shortString;
}
}
- 區別:
- 可逆演算法可以透過短字串還原為原字串,而不可逆演算法無法還原。
- 可逆演算法產生的短字串長度較長,而不可逆演算法產生的短字串長度較短。
- 使用演算法自動產生短字串無需頻繁讀寫資料庫,效能較好,但可能存在短字串衝突的問題,即不同的長字串可能產生相同的短字串。
最後列出完整的單元測試希望對您有用:
using HashidsNet;
using System.Security.Cryptography;
using System.Text;
namespace Dotnet9.Commons.Test;
[TestClass]
public class HashHelperUnitTest
{
public static string GetHashids(string sourceStr, int number = 9)
{
var hashids = new Hashids(sourceStr);
return hashids.Encode(number);
}
[TestMethod]
public void Hashids_Success()
{
var blogPostSlugStr = "Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet";
var encodeStr1 = GetHashids(blogPostSlugStr);
var encodeStr2 = GetHashids(blogPostSlugStr);
Assert.AreEqual(encodeStr1, encodeStr2);
}
[TestMethod]
public void Hashids_Best_Success()
{
var blogPostSlugStr = "Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet";
var encodeStr1 = blogPostSlugStr.GetHashids();
var encodeStr2 = ShortenString(blogPostSlugStr);
var encodeStr3 = ShortenString2(blogPostSlugStr);
Assert.IsTrue(encodeStr1.Length < encodeStr2.Length, "Hashids產生的短字串比Base64還短");
Assert.IsTrue(encodeStr1.Length < encodeStr3.Length, "Hashids產生的短字串還是短那麼一點點");
}
public static string ShortenString(string longString)
{
byte[] bytes = Encoding.UTF8.GetBytes(longString);
string shortString = Convert.ToBase64String(bytes);
return shortString;
}
public static string RestoreString(string shortString)
{
byte[] bytes = Convert.FromBase64String(shortString);
string longString = Encoding.UTF8.GetString(bytes);
return longString;
}
public static string ShortenString2(string longString)
{
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(longString));
string shortString = Convert.ToBase64String(hashBytes);
return shortString;
}
}
}
本文大部分引用知乎原文章:
原文標題:分享.NET/.NET 5 輕量級開源的將數字編碼成字串的加密(短 ID 產生)工具類別庫--hashids.net
原文連結:https://codedefault.com/p/lightweight-open-source-project-hashids-net-for-generating-short-ids-from-numbers