本文转自:http://www.cnblogs.com/CreateMyself/p/4856133.htmlhtml
不管是ASP.NET MVC仍是Web API框架,在从请求到响应这一过程当中对于请求信息的认证以及认证成功事后对于访问页面的受权是极其重要的,用两节来重点来说述这两者,这一节首先讲述一下关于这两者的一些基本信息,下一节将经过实战以及不一样的实现方式来加深对这两者深入的认识,但愿此文对你有所收获。算法
Identity表明认证用户的身份,下面咱们来看看此接口的定义安全
1
2
3
4
5
6
7
8
9
|
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。服务器
在WindowIdentity对象中的属性Groups返回Windows帐号所在的用户组,而属性IsGuest则用于判断此帐号是否位于Guest用户组中,最后还有一个IsSystem属性很显然表示该帐号是不是一个系统帐号。在对于匿名登陆中,该对象有一个IsAnonymous来表示该帐号是不是一个匿名帐号。而且其方法中有一个GetAnonymous方法来返回一个匿名对象的WindowsIdentity对象,可是此WindowsIdentity仅仅只是一个空对象,没法肯定对应的Windows帐号。cookie
咱们来看看此对象的定义框架
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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进行加密。 ide
var ticket = new FormsAuthenticationTicket(1, "cookie", DateTime.Now, DateTime.Now.AddMinutes(20), true, "userData", FormsAuthentication.FormsCookiePath); var encriptData = FormsAuthentication.Encrypt(ticket);
以上二者都有其对应的Identity类型,若是想自定义认证方式只需继承该类便可,它表示通常性的安全身份。该类继承于IIdentity接口。至于如何判断一个匿名身份只需经过用户名便可,若用户名为空则对象的属性IsAuthenticated为true,不然为false。函数
首先咱们来看看此接口编码
1
2
3
4
5
6
7
|
public
interface
IPrincipal
{
bool
IsInRole(
string
role);
IIdentity Identity {
get
; }
}
|
上述基于IIdentity接口的实现即WindowsIdentity和GenericIdentity,固然也就对应着Principal类型即WindowsPrincipal和GenericPrincipal,除此以外还有RolePrincipal,关于这三者就再也不叙述,咱们重点来看看下APiController中的IPrincipal属性。加密
咱们看看此User属性
1
|
public
IPrincipal User {
get
; }
|
继续看看此属性的获取
1
2
3
4
5
6
7
|
public
IPrincipal User
{
get
{
return
Thread.CurrentPrincipal;
}
}
|
到这里仍是不能看出什么,即便你用VS编译器查看也不能查看出什么,此时就得看官方的源码了。以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
HttpRequestContext RequestContext
{
get
{
return
ControllerContext.RequestContext;
}
set
{......}
}
public
IPrincipal User
{
get
{
return
RequestContext.Principal; }
set
{ RequestContext.Principal = value; }
}
|
到这里咱们看出一点眉目了
IPrincipal的属性User显然为当前请求的用户而且与HttpRequestContext中的属性Principal具备相同的引用。
咱们知道寄宿模式有两种,一者是Web Host,另外一者是Self Host,因此根据寄宿模式的不一样则请求上下文就不一样,咱们来看看Web Host中的请求上下文。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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也会一同进行修改。
咱们看看在此寄宿模式下的对于Principal的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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是第一个执行过滤器Filter,由于任何发送到服务器请求Action方法首先得认证其身份,而认证成功后的受权即Authorization固然也就在此过滤器以后了,它被MVC5和Web API 2.0所支持。下面用一张图片来讲明这两者在管道中的位置及关系
接下来咱们首先来看看第一个过滤器AuthenticationFilter的接口IAuthenticationFilter的定义:
1
2
3
4
5
6
7
8
|
public
interface
IAuthenticationFilter : IFilter
{
Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken);
Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken);
}
|
以上二者关于认证的方法都分别对应定义在Http协议的RFC2612以及RFC2617中,而且二者都是基于如下两点:
下面咱们详细查看每一个方法的内容:
此方法中的参数类型为HttpAuthenticationContext,表示为认证上下文,咱们看看此类的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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;
}
}
}
|
当执行为AuthenticateAsync方法被成功执行并返回一个具体的HttpActionResult,此时后续操做将终止,接下来进入第二个方法即【发送认证质询】阶段。
接下来咱们来看看此方法的具体实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
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;
}
}
}
|
(1)在Web API中使用AuthenticationFilter进行认证主要是如下三步
(2)经过上述描述咱们用三张示意图来对照着看
咱们知道Http协议中的认证方案有两种,一种是Basic基础认证,一种是Digest摘要认证