ASP.NET MVC和WebAPI已经是.NET Web部分的主流,刚开始时两个公用同一个管道,之后为了更加的轻量化(WebAPI是对WCF Restful的轻量化),WebAPI使用了新的管道,因此两者相关类的命名空间有细微差异,在使用时需要注意。
WebAPI学习系列目录如下,欢迎您的阅读!
快速入门系列--WebAPI--04在老版本MVC4下的调整
-
WebAPI与ASP.NET路由的异同
ASP.NET MVC的路由:Routes(RouteCollection)的线程安全,读写锁,GetReadLock, GetWriteLock。RouteTable.Routes.MapPageRoute(…);
命名空间为System.Web.Routing中
WebAPI的路由:首先介绍其相关类型,他们均是对Http报文的简易封装,System.Net.Http(HttpRequestMessage, HttpResponseMessage)。
命名空间为System.Web.Http.Routing中
HttpRouteHandler。
-
消息处理管道
还记的ASP.NET MVC中的核心是HttpHandler,而在WebAPI中其管道处理器是HttpMessageHandler。在实际中其通过职责链模式将委托通过InnerHandler(DelegationHandler)方式进行处理。其中,其中这个管道最开始的是httpServer,最末端的是HttpRoutingDispatcher(均在System.Web.Http命名空间下,支持异步模型),P108
Tip:额外想想也能理解WebAPI管道为什么更加轻量化,因而它只需要处理Json等类型数据,不需要考虑如页面、JS、静态资源等内容。
-
常见特性
Class: [RoutePrefix("api/demo")],针对具体类的路由设置,相对RouteConfig,粒度更细。
Method: [Route("action")]
[HttpGet], [HttpPost]
关于Web服务,其中比较难的概念一般都集中在安全,其相关概念非常的多,包括Windows相关认证模式、Forms认证、第三方认证、跨域访问等,接下来一一介绍。此外还会附加HttpClient、IOC框架的选择、服务幂等性、SignalR、EntLib中的EHAB等概念。
.NET安全模型:
Identiy表示用户身份, Identity AuthenticationType, IsAuthenticated, Name},常见的Identity有WindowsIdentity, FormsIdentity, GenericIdentity。P556
IPrincipal, 被成功实施授权的实体,等价于身份加角色,包括WindowsPrincipal(windows的权限组),GenericPrincipal, RolePrincipal(Membership组件和Roles组件) 。常见的认证方式通过"质询-应答"(challenge-Response)方式。
常见http认证方式,Basic和Digest,前者使用将认证凭证(用户名+密码)通过base64编码而未加密,但我们可以使用https传输来解决机密性问题。与此相关的两个过滤器, AuthenticationFilter和AuthorizationFilter。
补充ActionFilter概念,比如请求涉及大量运算,并且输入和输出一一对应(即相同的输入有相同的输出),那么可以考虑缓存Action。P585
Windows认证模式(均通过在IIS中设置身份认证模式)
WebHost寄宿下的安全:Windows认证模式,通过Basic, Digest认证方案,最终采用NTLM或者Kerberos协议。认证用户的Principal体现在HttpContext、当前线程、ApiControlelr。Keep-Alive,Fidder查看调用。
| 名称 | 状态 | 响应类型 |
| Active Directory客户端证书身份验证 | 已禁用 | HTTP 401 质询 |
| ASP.NET 模式 | 已禁用 | |
| Forms身份验证 | 已禁用 | HTTP 302 登录/重定向 |
| Windows身份验证 | 已禁用 | HTTP 401 质询 |
| 基本身份验证(Windows/Basic) | 已禁用 | HTTP 401 质询 |
| 匿名身份验证 | 已禁用 | |
| 摘要式身份验证(Windows/digest) | 已启用 | HTTP 401 质询 |
-
Basic认证
现在都是HTTP401 质询模型,只有forms是http 302 登录/重定向。这个关于basic的质询方式很有意思,就是当你请求时,出现http 401,会要求你输入用户名密码,输入后你输入的用户名和密码会被base64编码发送的服务器,形式是Basic YWRtaW46YWRtaW4=,这部分的head就是authentication。查看windows的凭据管理器,账号密码木有问题,但仍然不能通过验证,非常的伤感,自己试着加上域cn1\,结果OK了,感觉棒棒哒,哈哈,说明asp.net安全模型和windows有很好的整合性。
Basic模式的流程是,浏览器向服务器IIS以匿名的方式发送GET请求,IIS回复一个401 Unauthorized的响应,该响应用"www-authenticate"报头告诉客户端采用的认证方案(basic)和对应的领域(Realm, localhost)。浏览器收到响应弹出登录对话框,收集输入的账号密码组成字符串作为认证凭证,接下来,浏览器再次发送请求,在authorization包头中携带认证的方案和用户的凭证Basic YWRtaW46YWRtaW4=,IIS解密后认证,action顺利执行。
Base64:是网络常见的用于传输8bit字节代码的编码方式,用在http表单(包括隐藏的表单域)和http GET url中,base64编码的信息具有不可读性,但不具有机密性,使用时需要注意应用场景。
-
Digest认证
Digest认证仅仅适用于Domain模式,如果基于WorkGroup模式,也无法使用,接下来通过fiddler看看相应的HTTP消息头。
HTTP 401的响应:
WWW-Authenticate: Digest qop="auth",algorithm=MD5-sess,nonce="+Upgraded+v1e4fcae181b935afc3d94f30f5033141a25e3c7e4b83bd101c60cf10ea425a352c8959c8d47e643e5fc38f90cffe411be5f7a99033900ae4d",charset=utf-8,realm="Digest"
Digest认证传输用户凭证的哈希码,而不是明文。客户端首先匿名向服务器发送GET请求,服务器返回一个401响应,这个响应包含一个"WWW-Authenticate"报头,携带的信息包括。
| 参数 | 解释 |
| Digest | 认证方案 |
| Realm="Digest" | 领域 |
| Algorithm | 表示服务端支持的哈希算法,MD5-sess |
| Nonce | 服务端生成的唯一性标示,一般来说,IIS会利用当前时间戳以及请求的Etag(被请求变量的实体值)报头值来生成这个nonce |
| Qop(Quanlity of Protection) | IIS采用qop通知客户端采用的消息保护等级,可选值包括auth(authentication), auth-int(authentication-integrity),前者仅限于基本的认证,后者还确保传输内容的一致性。 |
输入账号密码的再一次请求(响应为200成功):
Authorization: Digest username="cn1\\she_s", realm="Digest", nonce="+Upgraded+v1e4fcae181b935afc3d94f30f5033141a25e3c7e4b83bd101c60cf10ea425a352c8959c8d47e643e5fc38f90cffe411be5f7a99033900ae4d", uri="/Sory.Entertainment.WebAPI/", algorithm=MD5-sess, response="9a6cb99fad4404cdd521e5db432f6b09", qop="auth", nc=00000001, cnonce="c77c05d93544b363"
其相关参数为:
| 参数 | 解释 |
| Username | 代表客户端的用户名,看来用户名还是可以截取的 |
| Qop | 最终采用的消息保护等级, qop="auth" |
| Algorithm | 最终采用的加密算法,MD5-sess |
| Nonce | 实际就是服务器端生成的nonce |
| cnonce | 客户端生成的nonce(c代表client),它可以对请求内容签名以确保内容未被篡改,可以帮助客户端对服务端实施认证(服务端能够证明知道该nonce,这些很适合防御跨站请求伪造的防御) |
| Nc(nonce count) | 它表示客户端针对同一个nonce发送请求的数量,一位着这是随着请求不断增加的数字,IIS可以通过nc代表的数字来防止"重放攻击",它会维护每个nonce的nc,如果请求携带的nc比这个少,会被认为是不合法的请求。 |
IIS在接受到第二次请求后,它先对请求进行合法性校验(比如nc的合法性),然后从Authentication报头提取用户名、nonce和加密算法计算出针对用户名真正的Digest,最终利用它与请求中提供的Digest进行比较确认密码的正确性,完成客户端认证。
Tip:
<script type="application/json" >
{"appName":"Firefox","requestId":"ee1fc1d3f30e4b4cba937703bee3ce10"}
</script>
<script type="text/javascript" src="http://localhost:13820/69ea419b05a141aaa5111affa4bb02fe/browserLink" async="async"></script>
这部分如何理解,与jsonP相关?
-
集成Windows认证, P610
无论问basic还是Digest认证,如果使用浏览器做客户端,第一次访问总需要在弹出框中输入,非常繁琐,并且密码在网络中传输,有安全风险,一般采用加盐的方式避免。集成Windows认证可以很好解决该问题,它默认以登录机器的Windows账号的名义来访问被授权的资源没,用户的密码被包含在请求携带的安全令牌中,非常的方便,该方式最终使用NTLM和Kerberos协议来完成。
NTLM协议(比较陈旧):采用质询/应答(Challenge/Response)消息交换模式,DC域控制器保存所用用户的相关信息。基本流程为:步骤1,用户输入账户密码登录主机,主机会缓存输入密码的哈希值,原始密码会丢失。如果视图访问服务器资源,需要向对方发送请求,请求中包含一个明文表示的用户名;步骤2,服务端接受请求,生成16位随机数(称为质询challenge),存储起来后以明文的形式发送给客户端;和Digest请求中nonce的意图完全一致;步骤3,客户端收到服务端的质询后,用在步骤1中保存的密码哈希值对其加密,然后将加密后的质询发送给服务端;步骤4,服务端收到加密质询后,会向DC发送针对客户端的验证请求(请求中包括,用户名、客户端密码加密后的质询和原始的质询);步骤5、6,DC根据用户名获得密码哈希值,对原始质询加密,再与服务端发送的质询比较,一致就为验证通过,否则失败。
Kerberos:这东西也算是困扰了小弟很多年,老看到,尤其每次注册windows时,呵呵,你懂得。实际上它是一种更搞笑安全的认证协议,过程更加的复杂,与NTLM相似,也包含三部分,客户端、服务器和KDC(Key Distribution Center,在windows域中,KDC有DC担当)。Kerberos实际是一种基于票据(Ticket)的认证方式,客户端要访问服务端的资源,首先要购买服务端认可的票据。也就是说,客户端在访问服务器前要先买好票,等待服务器验票后才能入场,但这票不能直接购买,首先需要认购权证(和粮票,股票认购权证相似)。这个认购权证和进入服务器的入场券均由KDC发售,感觉各种绕……相关详细内容暂时放一放。
在IIS中使用windows集成验证时,会看到provider的设置,有"negotiate"和"NTLM"两个选项,默认使用前者,其Provider包括"Negotiate: Kerberos",当然也可以自定义。此外,客户端需要在IE设置-》高级中,开启Windows集成认证,默认是开启的。在使用HttpClient时,可以使用以下方式,简化调用。
1 HttpClientHandler handler = new HttpClientHanlder(); 2 方式1: Handler.UseDefaultCredentials = true; 3 方式2: handler.Credentials = new NetworkCredentials("username", "password", "domainname"); 4 Using(HttpClient client = new HttpClient(handler)){}