@[toc] 前言 有三個重要的類Claim, ClaimsIdentity, ClaimsPrincipal,我們以一個持有合法證件的學生Bob做比方,ClaimsPrincipal就是持有證件的學生Bob,ClaimsIdentity就是學生Bob的證件駕照,Claim就是Bob駕照中的各種信息 ...
目錄
- 前言
- 基於聲明的認證(Claims-based Authentication)
- 在ASP.NET Core Identity中是如何實現的
- 類ClaimsPrincipal
- 考察另外一個重要的類ClaimsIdentity
- 在ASP.NET Core Identity中一同運行
- 總結
@
前言
有三個重要的類Claim, ClaimsIdentity, ClaimsPrincipal,我們以一個持有合法證件的學生Bob做比方,ClaimsPrincipal就是持有證件的學生Bob,ClaimsIdentity就是學生Bob的證件駕照,Claim就是Bob駕照中的各種信息。
下邊就開始圍繞上邊這段話展開描述:
基於聲明的認證(Claims-based Authentication)
在開始學習標識管理系統(Identity system)之前,很有必要搞清楚什麼是基於聲明的身份認證。
我們假設一個場景。Bob是一名大學生,準備去銀行為自己開戶。銀行工作人員需要Bob提供他的有效證件,於是Bob就把自己的駕照提供給了銀行工作人員。銀行工作人員可以從駕照上獲取到Bob的個人信息,例如姓名、出生日期和地址等。
Bob希望能夠享受到銀行針對大學生的優惠政策,於是銀行工作人員又請Bob提供了學生證,同時從上邊可以獲取到姓名、所在的大學名稱、院系以及學號等信息。(這裡提供別人的學生證一定是不行的!)
使用以上生活中典型的應用場景,可以幫助我們進一步去理解基於聲明(Claims-based Authentication)的身份認證。這個例子中Bob擁有兩個標識(Identity,就相當於有效的身份證明,即證明你是你的那張紙,也就是Identity):駕照+學生證。(當然還可以提供更多的Identity,比如護照、戶口本等等。)
好吧,我自己用文字越寫越怕不明白,通過上邊的這些文字,只需要清楚這麼幾點內容:
Claim
- 就是一個鍵值對,例如:name:Bob
Claim可以是姓名、出身日期、地址、所在大學、學號等等信息
Identity
- 很多條Claim組成了一個Identity
- Identity就是一個有效的身份證明 = 證明你是你的那張紙 = 駕照、學生證等等
一個人可以擁有很多個Identity
Bob去開戶,先提供了一個Identity(這裡就是駕照),接著又提供了一個Identity(學生證)
清楚了這些,我們繼續看
在ASP.NET Core Identity中是如何實現的
ASP.NET Core 是開源的,這能夠讓我們非常方便的去學習和理解它是如何構成並運行的。源碼可以去github上查看。
可以把源碼下載下來,然後查看源碼,路徑為:
corefx-master(解壓後主文件夾)/src/System.Security.Claims/src/System/Security
類ClaimsPrincipal
一個用戶(User)被聲明成ClaimsPrincipal類型(繼承自IPrincipal介面)。ClaimsPrincipal類來自System.Security.Claims命名空間。
public class ClaimsPrincipal : IPrincipal
{
...........
...........
public virtual IIdentity Identity { get; }
public virtual IEnumerable<ClaimsIdentity> Identities { get; }
public virtual IEnumerable<Claim> Claims { get; }
...........
...........
public virtual bool HasClaim(Predicate<Claim> match);
public virtual bool HasClaim(string type, string value);
public virtual bool IsInRole(string role);
...........
...........
}
從ClaimsPrincipal類中可以看到有一個返回類型為ClaimsIdentity集合的Identities屬性,代表著一個User可以擁有多個Identity。
在這裡的另外一個屬性Identity,不要被迷惑,他返回的是ClaimsPrincipal中主要的(如果有多個)那一個ClaimIdentity。
另外一個重要的屬性Claims,它返回了一個在ClaimsPrincipal中所有的ClaimsIdentity所包含得全部Claims的集合。
考察另外一個重要的類ClaimsIdentity
public class ClaimsIdentity : IIdentity
{
...........
...........
public virtual string AuthenticationType { get; }
public virtual string Name { get; }
public virtual bool IsAuthenticated { get; }
public virtual IEnumerable
public virtual IEnumerable
public virtual Claim FindFirst(string type);
public virtual bool HasClaim(string type, string value);
...........
...........
}
- 這裡的AuthenticationType屬性從字面意思就能很好的理解,返回認證的類型,在本示例中就可能是駕照或者學生證。在ASP.NET Core 中也可能是例如:微信、QQ、Cookies、Basic、Windows、Google等等。用AuthenticationType來驗證和確定與身份相關聯的聲明用的什麼方法。
- 還有一個IsAuthenticated屬性,用來獲取Identity是否被驗證,大家可能會感覺多餘,在沒有通過驗證的時候又怎麼會得到一個擁有Claims的Identity呢?有一個典型應用場景就是,允許游客訪問你的網站,允許使用購物車。這個游客一樣擁有由聲明(Claims)組成的標識(Identity),只是這位游客還沒有被驗證。這一非常重要的區別需要牢記。
在ASP.NET Core 創建一個ClaimsIdentity的時候,IsAuthenticationType總會被初始化為true。一個通過驗證的用戶一定會是true,相反未被驗證的游客,此屬性為false。 - Claims是組成Identity的全部Claim集合。
現在我們把這個假設的應用場景用圖示再總結一下:
在ASP.NET Core Identity中一同運行
上述內容在ASP.NET Core Identity 中使用Identity對象的簡單交互已經創建了一些API,例如SignInManager, UserManager ,RoleManager等,在ASP.NET Core 項目中通過依賴註入就可以使用它們。
例如,登錄管理就通過下邊一個public方法來完成登錄:
public virtual async Task SignInAsync(TUser user, AuthenticationProperties authenticationProperties,
string authenticationMethod = null)
{
var userPrincipal = await CreateUserPrincipalAsync(user);
if (authenticationMethod != null)
{
userPrincipal.Identities.First().AddClaim(new Claim
(ClaimTypes.AuthenticationMethod, authenticationMethod));
}
await Context.SignInAsync(IdentityConstants.ApplicationScheme,
userPrincipal,
authenticationProperties ?? new AuthenticationProperties());
}
總結
- Claim就是一個鍵值對,用來描述一個特新,比如
姓名:Bob
就是一個Claim,生日:2009.9.15
這也是一個Claim。其中姓名或生日就是這個Claim的一種類型,即Claimtype。 - 一組claim就構成了一個identity,具有這些claims的identity就是 ClaimsIdentity ,也可以把ClaimsIdentity理解為“證件”,駕照就是一種ClaimsIdentity,學生證也是一種ClaimIdentity。
- ClaimsIdentity的持有者就是ClaimsPrincipal ,一個ClaimsPrincipal可以持有多個ClaimsIdentity,就比如Bob既持有駕照(ClaimIdentity),又持有身份證(ClaimIdentity)。
理解了Claim, ClaimsIdentity, ClaimsPrincipal這三個概念,就能理解生成登錄Cookie為什麼要用下麵的代碼?
...
var claimsIdentity = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, loginName) }, "Basic");
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
await context.Authentication.SignInAsync(_cookieAuthOptions.AuthenticationScheme, claimsPrincipal);
...
要用Cookie代表一個通過驗證的主體,必須包含Claim, ClaimsIdentity, ClaimsPrincipal這三個信息,以一個持有合法駕照的人做比方,ClaimsPrincipal就是持有證件的人Bob,ClaimsIdentity就是證件駕照,"Basic"就是證件類型(這裡假設是駕照),Claim就是駕照中的信息。
如果感覺困擾,可以再看下dudu博客的這篇文章
這篇教程中,因為自己在理解的時候花了不少時間,請大家指證!