本文轉自: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摘要認證