系列
【從0開始.NET CORE認證】-2 使用.Net Core Identity和EF Core
回顧
還是回到第三篇文章中,我們在第三篇文章簡單的介紹了一下以下內容
- 怎么樣結合Identity認證給IdentityUser簽發Claims
- 怎么樣使用基於策略的權限驗證
- 怎么樣使用基於角色的權限驗證
- 怎么樣對IdentityUser進行Claim操作
其實第三篇並沒有完全結束,只是沒寫完,有空再寫。基於策略的權限驗證能做很多有趣的事情。
但是本篇開始會開啟OAuth認證
本次主要寫一下內容
OAuth介紹
大家可以去百度,但是百度來的一大堆專業詞匯,看的也非常迷惘!所以可以參考一下阮一峰大神的文章,關於解釋OAuth是什么
我這里還是簡單的畫個圖方便大家理解
1.這幅圖就是傳統的送貨方式
上面這幅圖會帶來什么問題?
- 業主告訴了快遞員密碼,在業主密碼沒更改的情況下,也就是說快遞員約等於業主。無論是否上下班都可以自由出入小區
- 快遞員泄露了密碼,會導致其他人也能冒充業主闖過小區門禁系統
- 業主如果每次收完貨就更改密碼,下次還是要把新密碼提供給快遞員。每次更改極其麻煩
所以為了解決問題,我們是不是中間加個流程,當快遞員需要送貨的時候,在小區門禁上提出申請,然后由業主同意,最后業主提供一個臨時密碼一樣的東西給快遞員,臨時密碼有有效期,1個小時就好了。這個問題是不是解決了
增加了345步驟,既可以保證小區的安全性,又可以完成送貨
更多OAuth知識請參閱
JWT介紹
如果把上述流程應用到互聯網開發中,現在開發模式大多屬於前后端分離的狀態,如果前端想要拿到后端的數據,后端說:你憑什么拿數據!依據我們前三篇講的,我們可以用Cookies來證明自己。
但是Cookies有個局限就是無法應用於分布式場景。
所以引入了JWT的概念——JWT 全稱Json Web Token,是一串字符串
JWT分成三部分
- 頭部
- 載荷
- 簽名
頭部負責存儲簽名的算法和令牌的類型,載荷部分存儲用戶的個人信息。簽名部分是對頭部和載荷加密后生成的哈希字符。
頭部和載荷負責base64加密,簽名使用哈希,最終構成一個長度很長的字符串。
這個字符串就是快遞員送貨中的臨時密碼,在OAuth中也被稱為access_token
.Net Core Identity接入OAuth生成JWT
.Net Core Identity已經實現了OAuth的框架,我們就用.Net Core Identity來實現一下OAuth
新建一個項目,名稱為:OAuthServer,然后稍微修改一下使其成為一個MVC頁面,增加一個Index頁面和Secert頁面,其中Secert頁面需要授權訪問
使用JWT需要引用以下擴展包
Microsoft.AspNetCore.Authentication.JwtBearer
在添加一個Login接口,負責頒發jwt
1 public IActionResult Login() 2 { 3 var claim = new[] 4 { 5 new Claim(JwtRegisteredClaimNames.Sub,"test"), 6 new Claim("test","test123") 7 }; 8 9 var keybytes = Encoding.UTF8.GetBytes(Constants.key); 10 var seckey = new SymmetricSecurityKey(keybytes); 11 var alorgthim = SecurityAlgorithms.HmacSha256; 12 var credential = new SigningCredentials(seckey, alorgthim); 13 14 var token = new JwtSecurityToken(Constants.Issuer, Constants.Audiance, claim, 15 notBefore: DateTime.Now, 16 expires: DateTime.Now.AddHours(2), 17 signingCredentials: credential 18 ); 19 20 var access_token = new JwtSecurityTokenHandler().WriteToken(token); 21 return Ok(new { access_token }); 22 }
其中Constrants類是我自定義的一個類
1 public class Constants 2 { 3 4 public const string Issuer = "http://localhost:8266"; 5 6 public const string Audiance = "http://localhost:8266"; 7 8 public const string key = "private_key_should_set_longer"; 9 10 }
運行,訪問/Home/Login接口
發現是可以生成JWT格式的Token了。
把拿到的token放到jwt.io解析一下,看下是什么東西
可以看到,如我們上文介紹的一樣,分成三個部分,頭部,載荷和簽名
使用JWT訪問被保護的資源
這個時候需要使用一下測試工具POSTMAN,有關如果在http頭部請求加入驗證,請查閱百度,本處不再講述
用戶提交了一個jwt格式的token過來,我們肯定是需要進行核驗的,如果我們不進行核驗,用戶隨隨便便就提交過來,豈不是保護資源約等於沒保護?
在Startup.cs文件中修改一下代碼
1 services.AddAuthentication("OAuth") 2 .AddJwtBearer("OAuth",config=> { 3 var keybytes = Encoding.UTF8.GetBytes(Constants.key); 4 var seckey = new SymmetricSecurityKey(keybytes); 5 config.TokenValidationParameters = new TokenValidationParameters 6 { 7 ValidIssuer = Constants.Issuer, 8 ValidAudience = Constants.Audiance, 9 IssuerSigningKey = seckey, 10 }; 11 });
然后我們用postman測試一下
可以發現成功訪問。
把Token放到url連接里面
平常開發接口,有些時候為了方便,不會去對http的頭部進行設置。所以會選擇把token放到url參數里面,這種情況怎么處理呢?
只需要更改一下代碼就行了
1 services.AddAuthentication("OAuth") 2 .AddJwtBearer("OAuth",config=> { 3 config.Events = new JwtBearerEvents() 4 { 5 OnMessageReceived = context => 6 { 7 if (context.Request.Query.ContainsKey("access_token")) 8 { 9 context.Token = context.Request.Query["access_token"]; 10 } 11 return Task.CompletedTask; 12 } 13 }; 14 var keybytes = Encoding.UTF8.GetBytes(Constants.key); 15 var seckey = new SymmetricSecurityKey(keybytes); 16 config.TokenValidationParameters = new TokenValidationParameters 17 { 18 ValidIssuer = Constants.Issuer, 19 ValidAudience = Constants.Audiance, 20 IssuerSigningKey = seckey, 21 }; 22 });
只需要偵聽OnMessageReceived事件,當請求的url中包含access_token就把它的值賦給上下文中的token
運行看下:
可以發現,成功訪問。
結束
好了,本章的JWT知識就到這里。