c#關(guān)于JWT跨域身份驗證的實現(xiàn)代碼
JSON Web Token(JWT)是目前最流行的跨域身份驗證解決方案。為了網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開發(fā)標(biāo)準(zhǔn)(RFC 7519),
該token被設(shè)計為緊湊且安全的,特別適用于分布式站點的單點登陸(SSO)場景。JWT的聲明一般被用來在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息,
以便于從資源服務(wù)器獲取資源,該token也可直接被用于認(rèn)證,也可被加密。
一、JWT的組成
下面是JWT的一段示例,分為三個部分,分別是頭部(header),載荷(payload)}和簽證(signature),他們之間用點隔開。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJpc3MiOiLmtYHmnIjml6Dlj4wiLCJleHAiOjE1NzExMDIxNTMsInN1YiI6InRlc3RKV1QiLCJhdWQiOiJVU0VSIiwiaWF0IjoiMjAxOS8xMC8xNSA5OjE1OjQzIiwiZGF0YSI6eyJuYW1lIjoiMTExIiwiYWdlIjoxMSwiYWRkcmVzcyI6Imh1YmVpIn19.
25IbZpAbSXBQsr2k3h0IzKRAC6z3OJTWg38VDtcEER8
二、和傳統(tǒng)session的對比
JWT是基于json的鑒權(quán)機(jī)制,而且是無狀態(tài)的,服務(wù)器端是沒有如傳統(tǒng)那樣保存客戶端的登錄信息的,這就為分布式開發(fā)提供了便利,
因為傳統(tǒng)的方式是在服務(wù)端保存session信息,session是保存在內(nèi)存中的,當(dāng)客戶量變大的時候,對服務(wù)器的壓力自然會增大,
最關(guān)鍵的是在集群分布式中,每一次登錄的服務(wù)器可能不一樣,那么可能導(dǎo)致session保存在其中一個服務(wù)器,而另外一個服務(wù)器被請求的
時候還是無狀態(tài),除非你再次登錄,這就造成了很大的麻煩,也有人說把session存放在專門的服務(wù)器,每次都去那個服務(wù)器請求,
我不認(rèn)為這是很好的解決方案,本來集群就是為了高可用,如果你配置session的服務(wù)器壞了,大家都跟著完蛋,所以JWT這種無狀態(tài)的方式
就非常適合這種分布式的系統(tǒng)。
三、代碼 JwtHelper
光說不練假把式,下面還是來一段代碼。
還是老方式,先用NuGet把JWT引用進(jìn)來,這里需要引入JWT和newtonsoft.json
如下圖所示:
然后就是生成JWT的方法。
static IJwtAlgorithm algorithm = new HMACSHA256Algorithm();//HMACSHA256加密 static IJsonSerializer serializer = new JsonNetSerializer();//序列化和反序列 static IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();//Base64編解碼 static IDateTimeProvider provider = new UtcDateTimeProvider();//UTC時間獲取 const string secret = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4aKpVo2OHXPwb1R7duLgg";//服務(wù)端 public static string CreateJWT(Dictionary<string, object> payload) { IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); return encoder.Encode(payload, secret); }
看到這段代碼,你說覺得怎么這么簡單,沒錯,就是這么簡單,這個方法是被我們引用進(jìn)來的這個JWT給封裝了,所以看起來很簡單
當(dāng)時我看到這里也是有點吃驚,不過我還是對源碼進(jìn)行了研究,下面貼出一段源碼給大家看看
如下所示,這段代碼是比較核心的代碼,在沒有傳遞header的時候,他幫你默認(rèn)加了header,
其實下面的這段代碼很容易看懂,無非就是對header和payload進(jìn)行base64加密(其實這里說加密也不是很恰當(dāng))。
這里的header你可以自己傳遞進(jìn)來。
public string Encode(IDictionary<string, object> extraHeaders, object payload, byte[] key) { if (payload is null) throw new ArgumentNullException(nameof(payload)); var segments = new List<string>(3); var header = extraHeaders is null ? new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) : new Dictionary<string, object>(extraHeaders, StringComparer.OrdinalIgnoreCase); header.Add("typ", "JWT"); header.Add("alg", _algorithm.Name); var headerBytes = GetBytes(_jsonSerializer.Serialize(header)); var payloadBytes = GetBytes(_jsonSerializer.Serialize(payload)); segments.Add(_urlEncoder.Encode(headerBytes)); segments.Add(_urlEncoder.Encode(payloadBytes)); var stringToSign = String.Join(".", segments.ToArray()); var bytesToSign = GetBytes(stringToSign); var signature = _algorithm.Sign(key, bytesToSign); segments.Add(_urlEncoder.Encode(signature)); return String.Join(".", segments.ToArray()); }
下面一段就是對JWT進(jìn)行驗證的代碼,這里的寫法都差不多,反正都是調(diào)用JWT里面的方法,我們傳遞參數(shù)即可。
public static bool ValidateJWT(string token, out string payload, out string message) { bool isValidted = false; payload = ""; try { IJwtValidator validator = new JwtValidator(serializer, provider);//用于驗證JWT的類 IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);//用于解析JWT的類 payload = decoder.Decode(token, secret, verify: true); isValidted = true; message = "驗證成功"; } catch (TokenExpiredException)//當(dāng)前時間大于負(fù)載過期時間(負(fù)荷中的exp),會引發(fā)Token過期異常 { message = "過期了!"; } catch (SignatureVerificationException)//如果簽名不匹配,引發(fā)簽名驗證異常 { message = "簽名錯誤!"; } return isValidted; }
四、調(diào)用
class Program { static void Main(string[] args) { //載荷(payload) var payload = new Dictionary<string, object> { { "iss","流月無雙"},//發(fā)行人 { "exp", DateTimeOffset.UtcNow.AddSeconds(10).ToUnixTimeSeconds() },//到期時間 { "sub", "testJWT" }, //主題 { "aud", "USER" }, //用戶 { "iat", DateTime.Now.ToString() }, //發(fā)布時間 { "data" ,new { name="111",age=11,address="hubei"} } }; //生成JWT Console.WriteLine("******************生成JWT*******************"); string JWTString = JwtHelper.CreateJWT(payload); Console.WriteLine(JWTString); Console.WriteLine(); //校驗JWT Console.WriteLine("*******************校驗JWT,獲得載荷***************"); string ResultMessage;//需要解析的消息 string Payload;//獲取負(fù)載 if (JwtHelper.ValidateJWT(JWTString, out Payload, out ResultMessage)) { Console.WriteLine(Payload); } Console.WriteLine(ResultMessage);//驗證結(jié)果說明 Console.WriteLine("*******************END*************************"); } }
結(jié)果如圖:
五、總結(jié)
1、因為json是通用的,所以jwt可以在絕大部分平臺可以通用,如java,python,php,.net等
2、基于jwt是無狀態(tài)的,jwt可以用于分布式等現(xiàn)在比較流行的一些框架中。
3、jwt本身不是加密的,所以安全性不是很高,別人知道了你的token就可以解析了,
當(dāng)然你自己也可以對jwt進(jìn)行加密,設(shè)置的過期時間不宜過長,同時不要保存一些重要的信息,如密碼。
4、盡量使用https,這也是為了安全。
5、JWT字節(jié)占用很少,非常的輕便,所以便于傳輸。
6、JWT一般放在http的頭部Header中傳輸。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:C# 實現(xiàn)PPT 每一頁轉(zhuǎn)成圖片過程解析
欄 目:C#教程
下一篇:c#自定義Attribute獲取接口實現(xiàn)示例代碼
本文標(biāo)題:c#關(guān)于JWT跨域身份驗證的實現(xiàn)代碼
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/4637.html
您可能感興趣的文章
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10關(guān)于nancy中的身份驗證
- 01-10C#中ZipHelper 壓縮和解壓幫助類
- 01-10關(guān)于C#中排序函數(shù)的總結(jié)
- 01-10關(guān)于C# Math 處理奇進(jìn)偶不進(jìn)的實現(xiàn)代碼
- 01-10C#中的委托使用
- 01-10關(guān)于finalize機(jī)制和引用、引用隊列的用法詳解
- 01-10淺談C#多線程簡單例子講解
- 01-10C#實現(xiàn)圖片上傳(PC端和APP)保存及 跨域上傳說明
- 01-10關(guān)于C#中ajax跨域訪問問題


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻 器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-11ajax實現(xiàn)頁面的局部加載
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10C#中split用法實例總結(jié)
- 01-10delphi制作wav文件的方法
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改