本文介紹如何保護API,無需看前邊文章也能明白吧。html
預備知識: git
http://www.cnblogs.com/cgzl/p/9010978.htmlgithub
http://www.cnblogs.com/cgzl/p/9019314.htmlweb
創建成熟度2級的 API請看這裏:json
http://www.javashuo.com/article/p-sryarofa-ct.html api
http://www.javashuo.com/article/p-nmpufjil-ee.html 跨域
http://www.javashuo.com/article/p-oxgmtvqz-dz.html瀏覽器
HATEOAS:http://www.javashuo.com/article/p-evqneumz-dv.html緩存
緩存和併發: http://www.javashuo.com/article/p-ccthjaxz-dq.html安全
保護API和其它: http://www.javashuo.com/article/p-fozgvvam-dk.html
本文所需項目代碼(右鍵另存, 後綴改成zip): https://images2018.cnblogs.com/blog/986268/201806/986268-20180612151833673-1851218969.jpg
認證/身份驗證 Authentication, 是驗證想要訪問特定資源的人/系統的身份的過程.
受權 Authorization, 是確認已認證的用戶擁有足夠的權限去作某些事的過程.
打個比喻: 認證是一我的能夠進入到房間的權限, 而受權則代表這我的能夠在房間內作哪些事.
認證的過程能夠和應用程序分開而且還能夠被其它的服務使用, 可是受權的過程一般是針對某個應用程序, 不一樣的角色會擁有不一樣的權限.
HTTP協議提供了一個協商訪問被保護資源的機制, 下圖就是HTTP認證:
標準的認證流程開始於一個訪問服務器被保護資源的匿名請求, HTTP服務器隨後處理了該請求並決定拒絕讓它訪問被保護的資源, 由於該請求沒有憑據; 隨後HTTP Server發送了一個WWW-Authenticate Header回去, 這表示它須要這套認證方案. 而後客戶端再次發送請求的時候包含了一個Authorization Header, 它的值符合HTTP Server的認證方案. 當服務器收到此次請求時, 它驗證了Authorization Header裏的憑據, 並讓請求經過了管道.
服務器能夠提供多種認證方案, 客戶端只需選擇其中一種便可, 上圖中使用的是Basic 認證方案. 還有其它的認證方案:
後兩種方案都僅限於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://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-2.1&tabs=visual-studio#require-https), 它建議ASP.NET Core web應用都應該調用HTTPS重定向中間件, 這樣就能夠把全部的HTTP請求轉換爲HTTPS.
只須要在Startup的Configure方法裏調用UseHttpsRedirection()方法便可:
而在ConfigureServices方法裏能夠配置這個中間件:
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須要在Startup的ConfigureServices方法完成:
針對整個應用啓用CORS須要在Configure方法裏調用下面的方法:
應該儘早的調用該方法, 以便在它後邊註冊的節點均可以被跨域訪問.
這是第一種方法, 使用的是lambda表達式.
注意URL地址結尾不要有/, 它會引發錯誤.
這種方法使用的是CorsPolicyBuilder 類, 它擁有Fluent API, 能夠串接方法調用:
第二種方法是使用策略.
在ConfigureServices裏配置好命名的策略:
在Configure方法裏使用該策略:
另外也能夠不適用UseCors(), 而是在下面這幾種級別指定使用該策略:
Action級別:
Controller級別:
全局Controller級別:
這麼用的話, 須要禁用CORS策略就:
關於CORS的具體配置, 仍是請參考官方文檔: https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1
速率限制是指限制被容許的請求到API(或某個特定的資源)。這樣就能夠保護API,避免一些非正常使用的場景,例如網絡爬蟲或請求太多而致使API的性能嚴重降低,Dos和DDos。針對這點咱們採起的節流策略是控制容許訪問API的請求的頻率/速率,它能夠決定特定的請求是否被容許。
例如客戶端只容許每小時有100個請求到達API,也能夠按天計算,還能夠帶着IP地址一塊兒限制。
響應的Header能夠用來表示速率限制,可是這些Header並非HTTP標準。這些header都以X-Rate-Limit開頭。
若是達到限制了,這些響應會返回429 Too many requests 狀態碼。有可能會包含一個Retry-After 響應Header,而響應的body應該包含解釋當前狀態的細節信息。固然這都是理論上要求的。
下面去實現,首先安裝這個庫 AspNetCoreRateLimit (https://github.com/stefanprodan/AspNetCoreRateLimit):
首先在Startup的ConfigureServices裏面註冊,用到了MemoryCache:
這裏配置的是IP限制,它容許有不少規則,這裏我只用了一個:針對全部的資源,每5分鐘最多3次請求。
如今,我須要註冊一個策略存儲和速率限制計數器的存儲,這兩個是被中間件使用。因此還須要註冊這兩個服務:
這裏都使用的是Singleton單例,由於咱們須要的是針對全局的請求來作操做。
接下來要在管道里添加中間件,它應該放在靠前的位置,在日誌和異常以後:
測試,發送一個請求看結果:
能夠看到5分鐘內還剩下兩次請求的配額。限制重置的時間大約在5分鐘以後。
發送請求超限以後,就會返回429:
Retry-After提示了再過294秒後能夠再試試。。。
而響應的body是這樣提示的:
咱們再組合幾個其它的規則:
如今容許5分鐘10次請求,可是每10秒鐘最多隻能有兩次請求。
第一次請求後:
5分鐘內還剩9次,而後我10秒內連續發送兩次請求,而後再發送一次請求:
這時超出了限制,Header裏:
提示6秒後能夠重試, 6秒後再次發送請求:
這個庫仍是挺靈活強大的,更多功能還須要看官方文檔。
業界一般會使用Swagger OpenAPI來對RESTful API進行格式化描述,而Swagger OpenAPI的當前版本是v3.
ASP.NET Core有一個第三方庫Swashbuckle,它支持Swagger,可是隻支持版本2,版本2有個重要的缺陷就是不支持Action重載,以前HATEOAS的文章裏提到過咱們須要使用這種重載。因此Swashbuckle暫時並非徹底合適,因此我就不裝它了。
就暫時不弄自動文檔了。。。
須要使用到xUnit和Moq,這裏不介紹了。
關於xUnit,我寫過幾篇文章,有興趣能夠參考下:
http://www.cnblogs.com/cgzl/p/8283610.html
http://www.cnblogs.com/cgzl/p/8287588.html
http://www.cnblogs.com/cgzl/p/8438019.html
http://www.cnblogs.com/cgzl/p/8444423.html
Moq的文章博客園應該有,若是須要的話,我能夠寫一下。
其它可能須要瞭解的包括:POSTMAN/Newman自動化測試,CI,CD,GraphQL等等。我就不介紹了
這個系列文章就到這了。
源碼(我還須要整理一下源碼,如今有點亂):https://github.com/solenovex/ASP.NET-Core-2.0-RESTful-API-Tutorial