您好,登錄后才能下訂單哦!
怎么在C#中利用jwt實現(xiàn)一個分布式登錄功能?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
在服務(wù)器存儲一份用戶登錄的信息,這份登錄信息會在響應(yīng)時傳遞給瀏覽器,告訴其保存為cookie,以便下次請求時發(fā)送給我們的應(yīng)用,這樣我們的應(yīng)用就能識別請求來自哪個用戶了,這就是傳統(tǒng)的基于session認(rèn)證。
在asp.net core中可以簡單實現(xiàn):
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); //使用靜態(tài)文件 app.UseStaticFiles(); //Cookie策略 //app.UseCookiePolicy(); //Session app.UseSession(); app.UseMvc(routes => { routes.MapRoute( name: "default", // template: "{controller=Home}/{action=Index}/{id?}"); //template: "{controller=Home}/{action=Server}/{id?}"); template: "{controller=Login}/{action=SignIn}/{id?}"); }); }
但是這種基于session的認(rèn)證使應(yīng)用本身很難得到擴展,隨著不同客戶端用戶的增加,獨立的服務(wù)器已無法承載更多的用戶,而這時候基于session認(rèn)證應(yīng)用的問題就會暴露出來。
傳統(tǒng)session的主要問題如下:
1.服務(wù)器壓力: 每個用戶經(jīng)過我們的應(yīng)用認(rèn)證之后,我們的應(yīng)用都要在服務(wù)端做一次記錄,以方便用戶下次請求的鑒別,通常而言session都是保存在內(nèi)存中,而隨著認(rèn)證用戶的增多,服務(wù)端的開銷會明顯增大。
2.擴展性: 用戶認(rèn)證之后,服務(wù)端做認(rèn)證記錄,如果認(rèn)證的記錄被保存在內(nèi)存中的話,這意味著用戶下次請求還必須要請求在這臺服務(wù)器上,這樣才能拿到授權(quán)的資源,這樣在分布式的應(yīng)用上,相應(yīng)的限制了負(fù)載均衡器的能力。這也意味著限制了應(yīng)用的擴展能力。
3.CSRF: 因為是基于cookie來進(jìn)行用戶識別的, cookie如果被截獲,用戶就會很容易受到跨站請求偽造的攻擊。
基于token的鑒權(quán)機制是無狀態(tài)的,它不需要在服務(wù)端去保留用戶的認(rèn)證信息或者會話信息,而是基于token去運算而實現(xiàn)鑒權(quán)。這就意味著基于token認(rèn)證機制的應(yīng)用不需要去考慮用戶在哪一臺服務(wù)器登錄了,這就為服務(wù)實現(xiàn)大規(guī)模分布式提供了基礎(chǔ)。
上圖是一種用token登錄的實現(xiàn)方式,類似的還有很多,雖然實現(xiàn)了分布式的登錄處理,但是由于不同的系統(tǒng)之間的不同實現(xiàn),導(dǎo)致開發(fā)量劇增。
這里推薦使用JWT——Json web token(官網(wǎng)鏈接)。一個典型的JWT看起來如下圖:
jwt為一個字符串,字符之間通過"."分隔符分為三個子串。注意JWT對象為一個長字串,各字串之間也沒有換行符,此處為了演示需要,特意分行并用不同顏色表示了。每一個子串表示了一個功能塊,總共有以下三個部分:JWT頭、有效載荷和簽名,將它們寫成一行如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE1OTM5NTU5NDMsInVpZCI6MTAsImV4cCI6MTU5Mzk1NTk3Mywic2NvcGVzIjpbImFkbWluIiwidXNlciJdfQ.VHpxmxKVKpsn2Iytqc_6Z1U1NtiX3EgVki4PmA-J3Pg
一般是將它放入HTTP請求的Header Authorization字段中
Authorization: Bearer
這里可以打開nuget:https://www.nuget.org/packages/JWT.Standard/,或者在vs中使用
輸入jwt.standard找到nuget包下載
1.生成jwt數(shù)據(jù)
在需要使用的地方輸入如下C#代碼:
var jwtp = new JWTPackage<UserModel>(new UserModel() { Id = "1", Name = "yswenli", Role = "Admin" }, 180, _pwd); var keyValuePair = jwtp.GetAuthorizationBearer(); context.HttpContext.Response.Headers[keyValuePair.Key] = keyValuePair.Value;
這樣就將需要的jwt內(nèi)容信息加入到Http頭部中,當(dāng)然可以使用如下方式,以參數(shù)數(shù)據(jù)的方式傳遞,從而避免跨域問題
var password = Guid.NewGuid().ToString("N"); var jwtp1 = new JWTPackage<User>(new User() { Id = "1", Name = "yswenli", Role = "Admin" }, 180, password); var sign = jwtp1.Signature;
2.jwt解析驗證
JWTPackage<T>中使用JWTPackage<T>.Parse方法解析jwt的內(nèi)容,如果內(nèi)容是header中的參數(shù),則快捷解析驗證代碼如下:
var result = string.Empty; try { if (context.HttpContext.Request.Headers.ContainsKey(keyValuePair.Key)) { var val = context.HttpContext.Request.Headers[keyValuePair.Key].ToString(); val = val.Replace(JWTPackage.Prex, ""); var jwt = JWTPackage<UserModel>.Parse(val, pwd); result = "OK"; } } catch (IllegalTokenException iex) { result = $"解析失敗:{iex.Message}"; } catch (TokenExpiredException tex) { result = $"解析失?。簕tex.Message}"; } catch (SignatureVerificationException sex) { result = $"解析失?。簕sex.Message}"; } catch (Exception ex) { result = $"解析失?。簕ex.Message}"; } return result;
經(jīng)過上述的簡單介紹,JWT不僅可用于認(rèn)證,還可用于信息交換,善用JWT有助于減少服務(wù)器請求數(shù)據(jù)的次數(shù)。但是如果不正確的使用JWT也會造成安全問題,主要幾點如下:
1.保護好secret私鑰,加密的密碼不能泄漏,否則就失去了簽名的意義了
2.Replay Attacks,JWT的消息體中最好加入生成時間,在后端中進(jìn)行時間判定,小于規(guī)定時間的直接攔截
3.不應(yīng)該在JWT的payload部分存放敏感信息,因為該部分是客戶端可解密的部分
4.建議的方式是通過SSL加密的傳輸(https協(xié)議),從而避免敏感信息被嗅探
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。