1. 程式人生 > >用ASP.NET Core 2.1 建立規範的 REST API -- 保護API和其它

用ASP.NET Core 2.1 建立規範的 REST API -- 保護API和其它

本文介紹如何保護API,無需看前邊文章也能明白吧

預備知識: 

建立成熟度2級的 API請看這裡:

認證和授權

認證/身份驗證 Authentication, 是驗證想要訪問特定資源的人/系統的身份的過程.

授權 Authorization, 是確認已認證的使用者擁有足夠的許可權去做某些事的過程.

打個比喻: 認證是一個人可以進入到房間的許可權, 而授權則表明這個人可以在房間內做哪些事.

認證的過程可以和應用程式分開並且還可以被其它的服務使用, 但是授權的過程通常是針對某個應用程式, 不同的角色會擁有不同的許可權.

HTTP協議提供了一個協商訪問被保護資源的機制, 下圖就是HTTP認證:

標準的認證流程開始於一個訪問伺服器被保護資源的匿名請求, HTTP伺服器隨後處理了該請求並決定拒絕讓它訪問被保護的資源, 因為該請求沒有憑據; 隨後HTTP Server傳送了一個WWW-Authenticate Header回去, 這表示它需要這套認證方案. 然後客戶端再次傳送請求的時候包含了一個Authorization Header, 它的值符合HTTP Server的認證方案. 當伺服器收到這次請求時, 它驗證了Authorization Header裡的憑據, 並讓請求通過了管道.

伺服器可以提供多種認證方案, 客戶端只需選擇其中一種即可, 上圖中使用的是Basic 認證方案

. 還有其它的認證方案:

  • 匿名 Anonymous 也可以當作是一種方案吧, 就當作是授權給所有人好了
  • Basic 認證方案, 它是一種比較老的方案, n年前經常被使用. 它太簡單了, 它的值是含有使用者名稱和密碼組成的字串, 並用冒號(:)連線, 並且編碼為Base64字串. 例如username為dave, 密碼為1234, 那麼Authorization Header的值就是: Authorization: Basic ZGF2ZToxMjM0.
  • Digest 認證方案, 它作為Basic的代替者出現的. 伺服器會給客戶端傳送一個隨機字串作為一個challenge(盤問, 質疑, 挑戰), 這個隨機字串叫做nonce(可以理解為臨時生成的字串). 而客戶端通過傳送一個帶有使用者名稱, 密碼, nonce和其它資訊的hash來進行認證.
  • Bear 認證方案, 它是最流行也是更安全的認證方案. 它使用Bearer Tokens (承載令牌) 來訪問由OAuth 2.0協議保護的資源. 任何擁有bearer token的人都可以訪問相關的資源. bearer token的生命週期通常很短, 會過期. 例子: Authorization: Bearer: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c.
  • NTLM認證方案, 它是NTLAN Manager的縮寫, 它是一種挑戰--響應的方案, 要比Digest更安全. 這種方案使用Windows憑據來轉化盤問的資料, 而不是使用編碼的憑據.
  • Negotiate 認證方案, 它會自動選擇NTLM方案和Kerberos協議中的一個, Kerboros協議比NTLM快.

後兩種方案都僅限於Windows系統.

這幾種方案裡Basic提供的保護程度/級別最低, 而Negotiate最高/強.

ASP.NET Core可選擇的認證提供商就很多了, 例如ASP.NET Core Identity. 但是它主要用於包含頁面的web應用, 例如MVC或Razor Page, 並不適用於REST/Web API, 所以不介紹它了.

如果應用部署在雲上, 可以使用Azure Active Directory(AAD)Azure Active Directory B2C (Azure AD B2C). 我沒用過, 就不介紹了.

第三方的認證提供商有很多: AspNet.Security.OpenIdConnect.Server(ASOS), IdentityServer4, OpenIddict, Pwdless.....

我一直在用Identity Server 4, 但是這裡不會深入介紹, 這裡主要介紹如何實現REST API, 如果有需要的話, 可以寫一系列關於Identity Server 4的文章.

選項很多, 但是要實現的話還需要了解JSON Web Tokens (JWT), 它是一個基於JSON的開放工業標準, 它用於為雙方表示一些宣告. 它提供了一種緊湊的, 自包含的方式在雙方之間用JSON物件來傳輸資訊.

JWT使用 HMAC secret RAS公有和私有鍵對(key pair) 這兩種方式來進行簽名.

JWT由三部分組成: header, payload, signature. 形式如下面的虛擬碼: [X=base64(header)].[Y=base64(payload)].[signature([X].[Y])] .

去這個網址可以更直觀的理解這三部分: jwt.io

JWT token最終是一個字串, 它的三個部分用點(.)分開, 前兩部分(header payload)是Base64編碼的字串; 最後一部分是前兩個Base64字串的組合, 也是用點(.)分開並進行了簽名, 如下圖:

 使用Bearer方案和JWT的流程如下:

配置專案, 在Startup的ConfigureServices裡:

如果使用Identity Server 4的話, 這裡就可以不這樣寫了.

首先我們配置使用Bearer認證方案, 然後通過AddJwtBearer設定一些引數. Configuration裡面的值可以放在appSettings.json裡面或者其它地方:

然後在Configure方法裡呼叫app.UseAuthentication()方法, 要在app.UseMvc()之前呼叫:

最後使用[Authorize]屬性標籤把CountryController保護起來, 也可以應用於Action級:

傳送不帶Authorization Header的請求來測試:

返回 401 Unauthorized 未授權.

返回的Header裡面告訴我們應該使用Bearer認證方案.

下面我們需要一個可以生成JWT token的節點, 針對本文我就在本專案裡建立這個節點吧:

請求token的地址是 /api/authentication, 請求token用的是Basic方案, Post方法裡就是先解碼, 驗證使用者名稱和密碼, 成功後呼叫GenerateToken生成token.

那就按要求再次傳送請求:

注意這裡usename:password的base64編碼是: dXNlcm5hbWU6cGFzc3dvcmQ=

現在我獲得了token, 然後我用token再次請求Country資源:

資源就可以正常的訪問了.

想要解析這個token, 需要到jwt.io:

箭頭處需要填上secret.

這個例子比較簡單, 實際應用中還是使用Identity Server 4之類的東西吧.

使用HTTPS

只需要在Startup的Configure方法裡呼叫UseHttpsRedirection()方法即可:

而在ConfigureServices方法裡可以配置這個中介軟體:

HSTS (HTTP 嚴格的傳輸安全協議)

web應用通過使用特殊的響應header可以選擇使用加強的安全協議OWASP(Open Web Application Security Project), HSTS(HTTP Strict Transport Security). 當所支援的瀏覽器接收到這個header的時候, 瀏覽器就會阻止任何通過HTTP到指定域名的通訊, 會使用HTTPS代替. 同時它也會阻止從瀏覽提的提示框點選的HTTPS.

為實現這個只需要在Startup的Configure裡使用:

 一般不建議在開發環境使用Hsts, 因為瀏覽器極有可能會快取HSTS 的header. 預設情況下, UseHsts會排除本地迴路的地址.

UseHsts會排除下列迴路宿主:

  • localhost : IPv4 迴路地址.
  • 127.0.0.1 : IPv4 迴路地址.
  • [::1] : IPv6 迴路地址.

可以在ConfigureServices方法裡對它進行配置:

CORS 跨域請求

配置註冊CORS需要在Startup的ConfigureServices方法完成:

針對整個應用啟用CORS需要在Configure方法裡呼叫下面的方法:

應該儘早的呼叫該方法, 以便在它後邊註冊的節點都可以被跨域訪問.

這是第一種方法, 使用的是lambda表示式.

注意URL地址結尾不要有/, 它會引起錯誤.

這種方法使用的是CorsPolicyBuilder 類, 它擁有Fluent API, 可以串接方法呼叫:

第二種方法是使用策略.

在ConfigureServices裡配置好命名的策略:

在Configure方法裡使用該策略:

另外也可以不適用UseCors(), 而是在下面這幾種級別指定使用該策略:

Action級別:

Controller級別:

全域性Controller級別:

這麼用的話, 需要禁用CORS策略就:

Rate Limiting 速率限制

速率限制是指限制被允許的請求到API(或某個特定的資源)。這樣就可以保護API,避免一些非正常使用的場景,例如網路爬蟲或請求太多而導致API的效能嚴重下降,Dos和DDos。針對這點我們採取的節流策略是控制允許訪問API的請求的頻率/速率,它可以決定特定的請求是否被允許。

例如客戶端只允許每小時有100個請求到達API,也可以按天計算,還可以帶著IP地址一起限制。

響應的Header可以用來表示速率限制,但是這些Header並不是HTTP標準。這些header都以X-Rate-Limit開頭。

  • X-Rate-Limit-Limit, 這個表示添加了限制幷包含了限制的有效期。
  • X-Rate-Limit-Remaining,表示該客戶還剩下多少個被允許的請求。
  • X-Rate-Limit-Reset,提供關於何時限制會被重置的時間資訊。

如果達到限制了,這些響應會返回429 Too many requests 狀態碼。有可能會包含一個Retry-After 響應Header,而響應的body應該包含解釋當前狀態的細節資訊。當然這都是理論上要求的。

首先在Startup的ConfigureServices裡面註冊,用到了MemoryCache:

這裡配置的是IP限制,它允許有很多規則,這裡我只用了一個:針對所有的資源,每5分鐘最多3次請求。

現在,我需要註冊一個策略儲存和速率限制計數器的儲存,這兩個是被中介軟體使用。所以還需要註冊這兩個服務:

這裡都使用的是Singleton單例,因為我們需要的是針對全域性的請求來做操作。

接下來要在管道里新增中介軟體,它應該放在靠前的位置,在日誌和異常之後:

測試,傳送一個請求看結果:

可以看到5分鐘內還剩下兩次請求的配額。限制重置的時間大約在5分鐘之後。

傳送請求超限之後,就會返回429:

Retry-After提示了再過294秒後可以再試試。。。

而響應的body是這樣提示的:

我們再組合幾個其它的規則:

現在允許5分鐘10次請求,但是每10秒鐘最多隻能有兩次請求。

第一次請求後:

5分鐘內還剩9次,然後我10秒內連續傳送兩次請求,然後再發送一次請求:

這時超出了限制,Header裡:

提示6秒後可以重試, 6秒後再次傳送請求:

這個庫還是挺靈活強大的,更多功能還需要看官方文件。

API 文件

業界通常會使用Swagger OpenAPI來對RESTful API進行格式化描述,而Swagger OpenAPI的當前版本是v3.

ASP.NET Core有一個第三方庫Swashbuckle,它支援Swagger,但是隻支援版本2,版本2有個重要的缺陷就是不支援Action過載,之前HATEOAS的文章裡提到過我們需要使用這種過載。所以Swashbuckle暫時並不是完全合適,所以我就不裝它了。

就暫時不弄自動文件了。。。

單元測試

需要使用到xUnit和Moq,這裡不介紹了。

關於xUnit,我寫過幾篇文章,有興趣可以參考下:

Moq的文章部落格園應該有,如果需要的話,我可以寫一下。

其它

其它可能需要了解的包括:POSTMAN/Newman自動化測試,CI,CD,GraphQL等等。我就不介紹了

這個系列文章就到這了。

相關推薦

ASP.NET Core 2.1 建立規範REST API -- HATEOAS

enume edi count DC tutorial 不知道 客戶 自適應 獨立 本文所需的一些預備知識可以看這裏: http://www.cnblogs.com/cgzl/p/9010978.html 和 http://www.cnblogs.com/cgzl/p/90

ASP.NET Core 2.1 建立規範REST API -- 保護API其它

本文介紹如何保護API,無需看前邊文章也能明白吧。 預備知識:  建立成熟度2級的 API請看這裡: 認證和授權 認證/身份驗證 Authentication, 是驗證想要訪問特定資源的人/系統的身份的過程. 授權 Authorization, 是確認已認證的

ASP.NET Core 2.1 建立規範REST API -- 翻頁/排序/過濾等

本文主要介紹一些常見情況的實現,包括:集合更新、翻頁、排序、過濾等等。但是仍然是Richardson成熟度頂多為2級的Web API,未達到RESTful API的標準和約束。 集合的更新操作 看這種更新集合的情況,原來資料庫裡中國存了4個城市(北平,上海,盛京,海參崴);

ASP.NET Core 2.1 建立規範REST API -- 快取併發

本文介紹快取和併發,無需看前邊文章也能明白吧。 快取 根據REST約束:“每個響應都應該定義它自己是否可以被快取”。本文就要介紹如何保證HTTP響應是可被快取的,這裡就要用到HTTP快取的知識,HTTP快取是HTTP標準的一部分(RFC 2616, RFC 7234)。 "除非效能可以得

ASP.NET Core 2.0 建立規範REST API -- GET POST

前綴 cat 編輯 derby 發生 就是 media 展現 targe 本文轉自:https://www.cnblogs.com/cgzl/archive/2018/05/23/9047626.html 本文所需的一些預備知識可以看這裏: http://www.cnblo

ASP.NET Core 2.0 建立規範REST API -- 預備知識 (2) + 準備專案

如果您對ASP.NET Core很瞭解的話,可以不看本文, 本文基本都是官方文件的內容。 ASP.NET Core 預備知識 專案配置 假設在專案的根目錄有這樣一個json檔案, 在ASP.NET Core專案裡我們可以使用IConfigurationRoot來使用該json檔案作為配置檔案,

ASP.NET Core 2.0 建立規範REST API -- 預備知識

什麼是REST REST 是 Representational State Transfer 的縮寫. 它是一種架構的風格, 這種風格基於一套預定義的規則, 這些規則描述了網路資源是如何定義和定址的. 一個實現了REST這些規則的服務就叫做RESTful的服務. 最早是由Roy Fielding提出的.

ASP.NET Core 2.0 建立規範REST API -- DELETE, UPDATE, PATCH Log

之前一篇文章介紹了POST和GET,這篇要介紹建立Richardson成熟度2級的DELETE, PUT, PATCH. DELETE 刪除資源 這個很簡單,以刪除City為例: 首先查詢Country,沒找到就返回404 Not Found;然後查詢City,沒找到也返回 404 No

從零開始學習 asp.net core 2.1 web api 後端api基礎框架(四)-建立Controller

建立一個Controllers目錄, 然後建立一個“控制器類” ProductController.cs, 它需要繼承Microsoft.AspNetCore.Mvc.Controller 在Controller裡面寫這個Get方法: namespace CoreBack

學習 ASP.NET Core 2.1:集成測試中使用 WebApplicationFactory

UNC enc sta 測試 修改 構造 creat -a msdn WebApplicationFactory 是 ASP.NET Core 2.1 新特性 MVC functional test infrastructure 中帶來的新東東,它封裝了 TestServe

asp.net core 2.1 將控制器抽離到類庫中

cat start service public 網站 類庫 class all app startup.cs的ConfigureServices中添加: public void ConfigureServices(IServiceCollection

ASP.NET Core 2.0 項目升級至 ASP.NET Core 2.1.3X

微信公眾號 code ima microsoft 訪問 nload 操作 更新 解決辦法 在上一篇文章ASP.Net Core 運行錯誤 Http Error 502.5 解決辦法的最後有提到說,最推薦的升級辦法是從2.0升級到2.1X版本. 操作如下 項目的例子直接使用h

再談使用X.PagedList.Mvc 分頁(ASP.NET Core 2.1

asp ram 默認 mvc 文本 它的 otn package www. 在以前的博文中寫過使用X.PagedList.Mvc組件來對ASP.NET MVC應用程序進行分頁,可以參考此篇隨筆:Asp.net MVC 使用PagedList(新的已更名 為X.PagedLi

ASP.NET core 2.1部署到 Centos 7

-m lrzsz arc -perm 安裝asp.net local ESS port pub 步驟要點: 一、關閉Linuxselinux: 操作方式: 1.永久關閉:打開/etc/selinux/config文件,設置SELINUX=disabled,註意,不是S

Asp.net Core 2.1使用 EF Core 簡單增刪改查操作數據庫

generic nuget ini gen 項目 pub sass .net 增刪改查 Asp.net Core 2.1使用 EF Core 簡單增刪改查操作數據庫 大概步驟如下5步: 1、創建項目(Asp.net Core 2.1項目) 2、項目使用EF Core 3、建

獨立部署asp.net core 2.1 Web應用程式

1.建立asp.net core 2.0  Web應用程式 新增引用: Microsoft.EntityFrameworkCore.Sqlite Microsoft.EntityFrameworkCore.Sqlite.Design 2.配置Sqlite資料庫 修改Startup.cs檔案

獨立部署asp.net core 2.1 Web應用程序

ring tar sign options \n rgs migration 局域網 引用 1.創建asp.net core 2.0 Web應用程序 添加引用: Microsoft.EntityFrameworkCore.Sqlite Microsoft.EntityFr

從零開始學習 asp.net core 2.1 web api 後端api基礎框架(七)-新增一個查詢單筆資料的方法

再寫一個查詢單筆資料的方法: [Route("{id}")] public JsonResult GetProduct(int id) { return new JsonResult(ProductService.Curre

從零開始學習 asp.net core 2.1 web api 後端api基礎框架(六)-把獲取資料的程式碼整理成一個服務

建立一個Services目錄, 然後建立一個 ProductService.cs類 我們把獲取資料的程式碼整理成一個ProductService, 然後保證程式執行的時候, 操作的是同一批資料: namespace CoreBackend.Api.Services { public

從零開始學習 asp.net core 2.1 web api 後端api基礎框架(五)-Routing 路由

路由有兩種方式: Convention-based (按約定), attribute-based(基於路由屬性配置的).  其中convention-based (基於約定的) 主要用於MVC (返回View或者Razor Page那種的). Web api 推薦使用attribute