本文介绍如何保护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