.net5 core webapi項目實戰之十五:身份驗證(上篇)


本篇將在webapi項目中加入身份認證功能,僅對授權的用戶提供服務,未授權的訪問給出提示信息。

 

1. 在傳統的web身份認證中,典型的認證過程是這樣的:用戶通過瀏覽器打開登錄頁,輸入帳號/密碼后提交,

Web服務器判斷帳號/密碼是否正確,如果正確會在服務器中生成一個Session對象標識用戶身份,

同時在響應Header中設置對應的Cookie字符串傳遞回瀏覽器

當用戶再次訪問頁面的時候,瀏覽器發送的請求頭帶上此Cookie字符串,Web服務器獲取請求頭中的Cookie字符串並解析,

然后與服務器中的Session對象比較,找出對應的Session,后續代碼中就可以使用代表該用戶身份的session信息了,如下圖:

 

2. .net core webapi是以微服務的方式來提供數據和計算服務的,自然需要使用更加合適的身份驗證模式,

為此微軟為我們提供了JWT(JSON Web Token)的認證授權實現,這是一種基於token的鑒權機制,

它不需要在服務端用Session去保存用戶的認證或會話信息,

只需要在請求/響應Header中加入簽名后的字符串(稱之為Token)就可以了,如下圖:

可以看到已經不需要在Web服務器上保存Session並維護Session Map信息了。

 

3. JWT認證生成的Token字符串格式如下 :

jouf980uojfosadjdfhaksd.sf23er4wehyuty3fasdf2sdzxz7xcvghret2kko9werdfartyy.cfg54dskj7nyuhj89sdfghj

它由三部分組成,分別是頭信息、有效載荷、簽名,中間以(.)分隔,每段的作用如下:

第一部分:header(頭信息)

編碼前的 header 信息包含算法(默認是 HMAC SHA256)和token類型定義(采用json格式,形式如下),

1 {
2  "alg": "HS256",
3  "typ": "JWT"
4  }

對此json對象進行Base64URL加密生成一個字符串,形如 "jouf980uojfosadjdfhaksd" 。

第二部分:Payload(有效載荷)

包含Claims(聲明),用來存放實際需要傳遞的數據,也是一個 JSON 對象,如下:

1  {
2    "sub": "testabcde",
3    "exp":"2020/01/02 09:20:39", 
4    "jti":1034758934
5    "userid":9527     
6    "username": "John Doe",
7  }

對此json對象進行Base64URL加密生成一個字符串,形如 "sf23er4wehyuty3fasdf2sdzxz7xcvghret2kko9werdfartyy" 。

Claims 中的字段名稱可以使用官方推薦的名稱也可以自己定義,如下表所示:

序號 名稱 描述 類別
1 iss (issuer) 簽發人 官方字段
2 exp (expiration time) 過期時間 官方字段
3 sub (subject) 主題 官方字段
4 aud (audience) 受眾 官方字段
5 nbf (Not Before) 生效時間 官方字段
6 iat (Issued At) 簽發時間 官方字段
7 jti (JWT ID) 編號 官方字段
8 xxxx 用戶自定義 私有字段
... xxxx 用戶自定義 私有字段
n xxxx 用戶自定義 私有字段

第三部分:Signature(簽名)

簽名的作用就是驗證前面兩部分的內容是否有被篡改,生成方式如下:

先將 "編碼過的header字符串"和"編碼過的payload字符串" 用 "." 拼接起來,

然后使用 Header 里面指定的簽名算法(默認是 HMAC SHA256)配合指定的密鑰(secret)對它們簽名,

最后將簽名的結果用Base64URL加密生成一個字符串,形如 "cfg54dskj7nyuhj89sdfghj" 。

 

注:因為Base64URL實際是對字符串做了一下轉換,大部分語言都是可以對其進行解密的,

所以對於敏感數據的傳遞需要先加密,加密方式可以參考本系列第十二篇。

 

4. .net5 core webapi中的編碼實現。

有了前面對原理的了解再編碼實現就比較簡單了,步驟如下:

4.1 先安裝 System.IdentityModel.Tokens.Jwt 和 Microsoft.AspNetCore.Authentication.JwtBearer  這兩個包。

安裝后在解決方案資源管理器中就可以看到這2個包了,如下:

 4.2 在Startup類的 ConfigureServices( ) 方法中配置JWT,增加如下代碼(紅色標注):

 1         public void ConfigureServices(IServiceCollection services)
 2         {
 3             services.AddControllers();
 4      
 5             services.AddScoped<IUserDao, MySqlUserDao>();
 6 
 7             services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();
 8   
 9         }

4.3 在 Startup 類的 Configure( ) 方法中啟用JWT,代碼如下紅色標注

 1         public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
 2         {
 3             if (env.IsDevelopment())
 4             {
 5                 app.UseDeveloperExceptionPage();
 6 
 7             } 
 8 
 9             loggerFactory.AddFile("Logs/log{Date}.txt");
10 
11             app.UseRouting();
12 
13             app.UseAuthentication();
14 
15             app.UseAuthorization();           
16 
17             app.UseEndpoints(endpoints =>
18             {
19                 endpoints.MapControllers();
20             });
21         }

4.4 在UsersController.cs中使用Jwt認證服務。

在終結點 ManageUsers( ) 上使用Jwt認證服務之前,我們先訪問一下API,看Jwt認證生效前是什么效果。

打開POSTMAN,訪問http://localhost:52384/api/users,結果如下:

可以看到在終結點 ManageUsers( ) 沒有使用Jwt認證時,可以正常訪問。

 

在UsersController.cs中添加引用 using Microsoft.AspNetCore.Authorization;

然后在終結點ManageUsers( )上加[Authorize]屬性啟用Jwt認證服務,代碼如下紅色標注)

1         [HttpGet]
2         [Authorize]
3         public ContentResult ManageUsers()
4         {
5             //...
6         }    

 重新編譯項目,然后在POSTMAN中訪問 http://localhost:52384/api/users,結果如下:

此時響應的是"401 Unauthorized" 沒有授權,並且在響應Header中多了一個"WWW-Authenticate"的KEY,Value="Bearer",Jwt身份認證已經生效了。

另:如果要對UsersController中所有終結點都啟用Jwt身份認證,只需要在UsersController這個類名上加[Authorize]屬性就可以了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM