Web APi之认证(Authentication)及授权(Authorization)【一】(十二)
前言
无论是ASP.NET MVC还是Web API框架,在从请求到响应这一过程中对于请求信息的认证以及认证成功过后对于访问页面的授权是极其重要的,用两节来重点来讲述这二者,这一节首先讲述一下关于这二者的一些基本信息,下一节将通过实战以及不同的实现方式来加深对这二者深刻的认识,希望此文对你有所收获。
Identity
Identity代表认证用户的身份,下面我们来看看此接口的定义
public interface IIdentity
{
// Properties
string AuthenticationType { get; } bool IsAuthenticated { get; } string Name {get; }
}
该接口定义了三个只读属性, AuthenticationType 代表认证身份所使用的类型, IsAuthenticated 代表是否已经通过认证, Name 代表身份的名称。对于AuthenticationType认证身份类型,不同的认证身份类型对应不同的Identity,若采用Windows集成认证,则其Identity为WindowsIdentity,反之对于Form表单认证,则其Identity为FormsIdentity,除却这二者之外,我们还能利用GenericIdentity对象来表示一般意义的Identity。
WindowsIdentity
在WindowIdentity对象中的属性Groups返回Windows账号所在的用户组,而属性IsGuest则用于判断此账号是否位于Guest用户组中,最后还有一个IsSystem属性很显然表示该账号是否是一个系统账号。在对于匿名登录中,该对象有一个IsAnonymous来表示该账号是否是一个匿名账号。并且其方法中有一个GetAnonymous方法来返回一个匿名对象的WindowsIdentity对象,但是此WindowsIdentity仅仅只是一个空对象,无法确定对应的Windows账号。
FormsIdentity
我们来看看此对象的定义
public class FormsIdentity : ClaimsIdentity
{ public FormsIdentity(FormsAuthenticationTicket ticket); protected FormsIdentity(FormsIdentity identity); public override string AuthenticationType { get; } public override IEnumerable<Claim> Claims { get; } public override bool IsAuthenticated { get; } public override string Name { get; } public FormsAuthenticationTicket Ticket { get; } public override ClaimsIdentity Clone();
}
一个FormsIdentity对象是通过加密过的认证票据(Authentication Ticket)或者是安全令牌(Security Token)来创建,被加密的内容或者是Cookie或者是请求的URl,下述就是通过FormsIdentity来对Cookie进行加密。
var ticket = new FormsAuthenticationTicket(, "cookie", DateTime.Now, DateTime.Now.AddMinutes(), true, "userData", FormsAuthentication.FormsCookiePath); var encriptData = FormsAuthentication.Encrypt(ticket);
GenericIdentity
以上两者都有其对应的Identity类型,如果想自定义认证方式只需继承该类即可,它表示一般性的安全身份。该类继承于IIdentity接口。至于如何判断一个匿名身份只需通过用户名即可,若用户名为空则对象的属性IsAuthenticated为true,否则为false。
Principal
这个对象包含两个基本的要素即基于用户的安全身份以及用户所具有的权限,而授权即所谓的权限都是基于角色而绑定,所以可以将此对象描述为:【身份】+【角色】。
首先我们来看看此接口
public interface IPrincipal
{ bool IsInRole(string role); IIdentity Identity { get; }
}
上述基于IIdentity接口的实现即WindowsIdentity和GenericIdentity,当然也就对应着Principal类型即WindowsPrincipal和GenericPrincipal,除此之外还有RolePrincipal,关于这三者就不再叙述,我们重点来看看下APiController中的IPrincipal属性。
APiController中User
我们看看此User属性
public IPrincipal User { get; }
继续看看此属性的获取
public IPrincipal User
{
get
{
return Thread.CurrentPrincipal;
}
}
到这里还是不能看出什么,即使你用VS编译器查看也不能查看出什么,此时就得看官方的源码了。如下:
public HttpRequestContext RequestContext
{
get
{
return ControllerContext.RequestContext;
}
set
{......}
} public IPrincipal User
{
get { return RequestContext.Principal; }
set { RequestContext.Principal = value; }
}
到这里我们看出一点眉目了
IPrincipal的属性User显然为当前请求的用户并且与HttpRequestContext中的属性Principal具有相同的引用。
那么问题来了,HttpRequestContext又是来源于哪里呢?
我们知道寄宿模式有两种,一者是Web Host,另一者是Self Host,所以根据寄宿模式的不同则请求上下文就不同,我们来看看Web Host中的请求上下文。
- Web Host
internal class WebHostHttpRequestContext : HttpRequestContext
{
private readonly HttpContextBase _contextBase;
private readonly HttpRequestBase _requestBase;
private readonly HttpRequestMessage _request; public override IPrincipal Principal
{
get
{
return _contextBase.User;
}
set
{
_contextBase.User = value;
Thread.CurrentPrincipal = value;
}
}
}
从这里我们可以得出一个结论:
Web Host模式下的Principal与当前请求上下文中的User具有相同的引用,与此同时,当我们将属性Principal进行修改时,则当前线程的Principal也会一同进行修改。
- Self Host
我们看看在此寄宿模式下的对于Principal的实现
internal class SelfHostHttpRequestContext : HttpRequestContext
{
private readonly RequestContext _requestContext;
private readonly HttpRequestMessage _request; public override IPrincipal Principal
{
get
{
return Thread.CurrentPrincipal;
}
set
{
Thread.CurrentPrincipal = value;
}
} }
在此模式我们可以得出结论:
Self Host模式下的Principal默认是返回当前线程使用的Principal。
接下来我们来看看认证(Authentication)以及授权(Authorization)。
AuthenticationFilter
AuthenticationFilter是第一个执行过滤器Filter,因为任何发送到服务器请求Action方法首先得认证其身份,而认证成功后的授权即Authorization当然也就在此过滤器之后了,它被MVC5和Web API 2.0所支持。下面用一张图片来说明这二者在管道中的位置及关系
接下来我们首先来看看第一个过滤器AuthenticationFilter的接口IAuthenticationFilter的定义:
public interface IAuthenticationFilter : IFilter
{ Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken); Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken);
}
该接口定义了两个方法,一个是 AuthenticateAsync ,它主要认证用户的凭证。另一个则是 ChallengeAsync ,它主要针对于在认证失败的情况下,向客户端发送一个质询(Chanllenge)。
以上两者关于认证的方法都分别对应定义在Http协议的RFC2612以及RFC2617中,并且两者都是基于以下两点:
如果客户端没有发送任何凭证到服务器,那么将返回一个401(unauthorized)响应到客户端,在返回到客户端的响应中包括一个WWW-Authenticate头,在这个头中包含一个或多个质询,并且每个质询将指定被服务器识别的认证组合。
在从服务器响应返回一个401到客户端后,客户端将在认证头里发送所有的凭证。
下面我们详细查看每个方法的内容:
AuthenticateAsync
此方法中的参数类型为HttpAuthenticationContext,表示为认证上下文,我们看看此类的实现
public class HttpAuthenticationContext
{ public HttpAuthenticationContext(HttpActionContext actionContext, IPrincipal principal)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
} ActionContext = actionContext;
Principal = principal;
} public HttpActionContext ActionContext { get; private set; } public IPrincipal Principal { get; set; } public IHttpActionResult ErrorResult { get; set; } public HttpRequestMessage Request
{
get
{
Contract.Assert(ActionContext != null);
return ActionContext.Request;
}
}
}
在构造函数中通过Action上下文和认证的用户的Principal属性进行初始化,而属性ErrorResult则返回一个HttpActionResult对象,它是在认证失败的情况直接将错误消息返回给客户端。我们应该能想到请求到Action方法上的AuthenticationFilter可能不止一个,此时Web API会通过FilterScope进行排序而形成一个AuthenticationFilter管道,紧接着认证上下文会通过当前的Action请求上下文以及通过APiController的User属性返回的Principal而被创建,最终认证上下文会作为AuthenticationFilter中的AuthenticateAsync方法的参数并进行调用。
当执行为AuthenticateAsync方法被成功执行并返回一个具体的HttpActionResult,此时后续操作将终止,接下来进入第二个方法即【发送认证质询】阶段。
ChallengeAsync
绝大多数认证基本上都是采用【质询-应答】方式,服务器向端客户端发出质询要求来提供凭证,若客户端在执行AuthenticateAsync方法后,认证未成功,此时服务器端将通过ChallengeAsync方法发送认证质询。
接下来我们来看看此方法的具体实现
public class HttpAuthenticationChallengeContext
{
private IHttpActionResult _result; public HttpAuthenticationChallengeContext(HttpActionContext actionContext, IHttpActionResult result)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
} if (result == null)
{
throw new ArgumentNullException("result");
} ActionContext = actionContext;
Result = result;
} public HttpActionContext ActionContext { get; private set; } public IHttpActionResult Result
{
get
{
return _result;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
} _result = value;
}
} public HttpRequestMessage Request
{
get
{
Contract.Assert(ActionContext != null);
return ActionContext.Request;
}
}
}
很显然,当调用AuthenticateAsync方法完成认证工作后,此时ErrorResult将返回一个具体的HttpActionResult,然会将Action上下文以及具体的HttpActionResult传递到构造函数中进行初始化HttpAuthenticationChallgeContext,最后依次调用ChallengeAsync方法,当此方法都被执行后,此类中的Result属性也就返回一个具体的HttpActionResult对象,此对象将创建相应的HttpResponseMessage对象,并回传到消息处理管道中并作出响应从而发出认证质询。
总结
(1)在Web API中使用AuthenticationFilter进行认证主要是以下三步
Web API会为每个需要被调用Action方法创建所有可能的AuthenticationFilter列表,若有多个则通过FilterScope来进行排序,最终形成AuthenticationFilter管道。
Web API将为AuthenticationFilter管道中的每一个过滤器依次调用AuthenticateAsync方法,在此方法中每个AuthenticationFilter将验证来自客户端的Http请求凭证,即使在认证过程中触发到了错误,此时进程也不会终止。
若认证成功,Web API将调用每个AuthenticationFilter的ChallengeAsync方法,接下来每一个AuthenticationFilter将通过此方法做出质询响应。
(2)通过上述描述我们用三张示意图来对照着看

认证方案
我们知道Http协议中的认证方案有两种,一种是Basic基础认证,一种是Digest摘要认证
Basic基础认证
此认证是在客户端将用户名和密码以冒号的形式并用Base64明文编码的方式进行发送,但是不太安全,因为未被加密,在此基础上采用Https信息通道加密则是不错的认证方案。
Digest摘要认证
此认证可谓是Basic基础认证的升级版,默认是采用MD5加密的方式,在一定程度上算是比较安全的,其执行流程和Basic基础认证一样,只是生成的算法不同而已。
未完待续:接下来将通过认证方案手动通过不同的方式来实现认证。。。。。。
Web APi之认证(Authentication)及授权(Authorization)【一】(十二)的更多相关文章
- mongodb的认证(authentication)与授权(authorization)
一小白瞎整mongodb,认证部分被折磨的惨不忍睹,看厮可怜,特查了一下文档,浅显地总结一下mongodb认证(authentication)与授权(authorization)的联系. 创建的所有用 ...
- [转].net中的认证(authentication)与授权(authorization)
本文转自:http://www.cnblogs.com/yjmyzz/archive/2010/08/29/1812038.html 注:这篇文章主要给新手看的,老手们可能会觉得没啥营养,就请绕过吧. ...
- .net中的认证(authentication)与授权(authorization)
“认证”与“授权”是几乎所有系统中都会涉及的概念,通俗点讲: 1.认证(authentication) 就是 "判断用户有没有登录?",好比windows系统,没登录就无法使用(不 ...
- 认证 (authentication) 和授权 (authorization) 的区别
authorization 授权 authentication 身份认证 用户认证流程: 1.用户使用username和password登录 2.系统验证这个password对于该username是正 ...
- 【转】认证 (authentication) 和授权 (authorization) 的区别
以前一直分不清 authentication 和 authorization,其实很简单,举个例子来说: 你要登机,你需要出示你的身份证和机票,身份证是为了证明你张三确实是你张三,这就是 authen ...
- Web Api 2 认证与授权 2
HTTP Message Handler 在 Web Api 2 认证与授权 中讲解了几种实现机制,本篇就详细讲解 Message Handler 的实现方式 关于 Message Handler 在 ...
- Web APi之认证(Authentication)两种实现方式【二】(十三)
前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底 ...
- Web APi之认证(Authentication)两种实现方式后续【三】(十五)
前言 之前一直在找工作中,过程也是令人着实的心塞,最后还是稳定了下来,博客也停止更新快一个月了,学如逆水行舟,不进则退,之前学的东西没怎么用,也忘记了一点,不过至少由于是切身研究,本质以及原理上的脉络 ...
- 转 Web APi之认证(Authentication)两种实现方式【二】(十三)
前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再废叙述废话. 序言 对于所谓的认证说到 ...
- Web APi之认证
Web APi之认证(Authentication)两种实现方式后续[三](十五) 前言 之前一直在找工作中,过程也是令人着实的心塞,最后还是稳定了下来,博客也停止更新快一个月了,学如逆水行舟,不 ...
随机推荐
- canvas图片处理
1.灰度 .299 * r + .587 * g + .114 * b; 2.连环画效果 R = |g – b + g + r| * r / 256 G = |b – g + b + r| * r / ...
- [IOS]cocoapos 两个ruby源的对比
最近需要使用一些动态类库,cocoapods比较好用,能帮助管理这些类库,百度一下也能找到很多cocoapods配置方法,这里不赘述,我想要讲的是在配置的时候一般都会推荐这样做 $ gem sourc ...
- python 根据现有文件树创建文件树
# -*- coding: utf-8 -*- import os, errno def fileName(path):#获取文件夹 str = '' for i in range(1,len(pat ...
- 另类的表单数据"序列化"
背景:最近在做项目时,由于编辑页面需要提交的数据量有些多,而且在提交前还需要做一些逻辑处理,所以如果按照正常的方式,一个个的获取值然后拼接json对象传到后台的话相对工作量较大,而且容易出错,后期的维 ...
- HTML打折计算价格
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <met ...
- linux下打包zip文件
zip [参数] [打包后的文件名] [打包的目录路径] linux zip命令参数列表:-a 将文件转成ASCII模式-F 尝试修复损坏的压缩文件 -h 显示帮助界面-m 将文件压 ...
- 浏览器中CSS的BUG
对于web2.0的过度,请尽量用xhtml格式写代码,而且DOCTYPE 影响 CSS 处理,作为W3C的标准,一定要加 DOCTYPE声明. 其它请参考:CSS hack 针对IE6,IE7,fir ...
- JS简介,如何快熟JS。打下结实基础。
JS决定网页的行为,有行为就有逻辑,而计算机只是人工智能,你给它什么样的指令,它就会按照你的指令去运行. 有人会问,既然是给出指令,那还需要什么逻辑? 这里我举一个简单的小例子来说明一下! 到你想输入 ...
- Python 的简单图形界面编程【草】
可用方案 Tkinter python官方附带,方便,但听说存在乱码问题 wxPython 更成熟一些,但需要额外安装(大约50M) pyQt 授权不够宽松 最短代码 Tkinter 待补充 wxPy ...
- 在MySQL的InnoDB存储引擎中count(*)函数的优化
写这篇文章之前已经看过了很多数据库方面的优化内容,大部分都是加索引.使用事务.要什么select什么等等.然而,只是停留在阅读的层面上,很少有实践,因为没有遇到真实的项目,一切都是纸上谈兵.实践是检验 ...