溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何入門ASP.NETCore中dentity

發(fā)布時(shí)間:2021-09-16 11:46:02 來源:億速云 閱讀:104 作者:柒染 欄目:開發(fā)技術(shù)

如何入門ASP.NETCore中dentity ,很多新手對此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

其實(shí) Identity 也是認(rèn)證系統(tǒng)的一個(gè)具體使用,大家一定要把 Authentication 和 Identity 當(dāng)作是兩個(gè)東西,一旦混淆,你就容易陷入進(jìn)去。

下面就來說一下 ASP.NET Core 中的認(rèn)證系統(tǒng)是怎么樣一回事。不要怕,其實(shí)很簡單,全是干貨~

Getting Started

大家應(yīng)該還記得在上一篇中的奧巴馬先生吧,他現(xiàn)在不住在華盛頓了,他到中國來旅游了,現(xiàn)在住在北京,這幾天聽說西湖風(fēng)景不錯(cuò),于是在 12306 定了一張北京到杭州的高鐵票。取到票之后,他向我們展示了一下:

如何入門ASP.NETCore中dentity

今天是11.11號,奧巴馬很開心,原因你懂的??斓匠霭l(fā)的時(shí)間了,于是,拿著票走到了火車站檢票口,剛把身份證和火車票遞給檢票員。“cut”,導(dǎo)演喊了一聲。尼瑪原來是在拍電影呢~

導(dǎo)演說:奧巴馬,你演的太爛了,別演了,你來演檢票員吧,讓旁邊小李來演要出行路由的奧巴馬吧。奧巴馬不情愿的說了一聲:“好吧,希望小李能夠受的了你”。

“action”,導(dǎo)演又喊了一聲,故事開始了~

AuthenticationManager

奧巴馬當(dāng)了檢票員以后,特別高興,因?yàn)樗袡?quán)利了呀,他可以控制別人能不能上車了,說不定還能偷偷放幾個(gè)人進(jìn)去撈點(diǎn)外快呢。

得知了他能干什么以后,他覺得檢票員這個(gè)名字簡直太 low 了,很快,他就有了一個(gè)新的高大上的名字,叫:認(rèn)證管理員(AuthenticationManager),而且,他覺得他自己應(yīng)該處在整個(gè)核心位置,為什么呢?你想想看,那么龐大的一套鐵路載人系統(tǒng),能不能有收入有錢賺,全靠他給不給放人進(jìn)去,如果一個(gè)人都不放進(jìn)去,另外那一大幫人只能去喝西北風(fēng)了。

到這里,聰明的同學(xué)可能已經(jīng)知道奧巴馬把他自己放在怎么樣一個(gè)核心位置了。對,他把自己放到了 HttpContext 里面。怎么樣? 夠核心吧。

這里延伸第一個(gè)知識點(diǎn):AuthenticationManager 所處的位置

如何入門ASP.NETCore中dentity

有同學(xué)在上面的截圖里面發(fā)現(xiàn)了 public abstract ClaimsPrincipal User { get; set; }, 這不就是我們上一篇中講到的 “ 證件當(dāng)事人 ” ,現(xiàn)在小李扮演的那個(gè)角色么? 對,這個(gè) User 就是本文中的小李,被你提前發(fā)現(xiàn)他躲著這里了,嘿嘿。

還有一個(gè)知識點(diǎn),就是 AuthenticationScheme,什么意思呢? 且看
 奧巴馬敢把自己放在這么核心的位置也是有他的能力的,怎么講呢? 比如說在檢票的時(shí)候,別人遞過來一張身份證和一張火車票,那怎么樣驗(yàn)證這兩個(gè)證件是合法的呢? 以下就是奧巴馬提出的針對兩種證件的驗(yàn)證方案:

方案1、針對身份證的驗(yàn)證,可以查看其本人是否和身份證頭像是否一致,年齡是否符合當(dāng)事人具體年齡。

方案2、針對火車票的驗(yàn)證,可以看車次,時(shí)間是否符合發(fā)車目標(biāo),另外可以看車票上的身份號碼是否和身份證一致。

其中,這每一種方案,就對應(yīng)一個(gè) AuthenticationScheme(驗(yàn)證方案名稱),是不是明白了。

這就是第二個(gè)知識點(diǎn) AuthenticationScheme 很重要。

知道了奧巴馬的職責(zé)后,就很容易的把代碼寫出來了:

public abstract class AuthenticationManager
{

  //AuthenticateContext包含了需要認(rèn)證的上下文,里面就有小李
  public abstract Task AuthenticateAsync(AuthenticateContext context);
  
  //握手
  public abstract Task ChallengeAsync(string authenticationScheme, AuthenticationProperties properties, ChallengeBehavior behavior);
  
  //登入
  public abstract Task SignInAsync(string authenticationScheme, ClaimsPrincipal principal, AuthenticationProperties properties);
  
  //登出
  public abstract Task SignOutAsync(string authenticationScheme, AuthenticationProperties properties);
}

奧巴馬做為一個(gè)檢票員,有一個(gè)認(rèn)證方法,AuthenticateAsync() ,注意這是其一個(gè)核心功能,其他幾個(gè)都可以沒有,但是唯獨(dú)不能沒有這個(gè)功能,沒有的話他就不能稱之為一個(gè)檢票員了。

然后還有一個(gè)握手ChallengeAsync,登入SignInAsync和登出SignOutAsync,下面說說筆者對這三個(gè)方法的理解吧。

ChallengeAsync:是社區(qū)協(xié)議文件 RFC2167 定義的關(guān)于在HTTP Authentication 過程中的一種關(guān)于握手的一個(gè)過程,主要是摘要認(rèn)證(digest authentication)。

是不是有點(diǎn)專業(yè),看不懂,沒事,有通俗版本的。 小李要進(jìn)站了,這個(gè)時(shí)候小李問了一下我們的檢票員奧巴馬先生。

  1. 小李:“你好,檢票員,我可以進(jìn)站嗎?”

  2. 檢票員奧巴馬:“要趕火車嗎?可以啊,請出示你的證件?”

  3. 小李:“好的,這是我的證件,你檢查一下?”

  4. 檢票員奧巴馬:“嗯,證件沒問題,進(jìn)去吧”

這樣一個(gè)過程就是握手(digest-challenge)或者叫問答的一個(gè)過程,明白了 ChallengeAsync 的原理了吧? 是不是很簡單。

SignInAsync,SignOutAsync:個(gè)人覺得這兩個(gè)不應(yīng)該放在這里,因?yàn)椴⒉粚儆谡J(rèn)證的職責(zé),也不屬于協(xié)議規(guī)定的內(nèi)容。但是這兩個(gè)方法確實(shí)需要抽象,應(yīng)該單獨(dú)抽取一個(gè)接口存放,至于為什么這樣做,或許是因?yàn)橐韵略颍?/p>

1、對登入登出的抽象是和認(rèn)證緊密結(jié)合的,大多數(shù)情況下認(rèn)證資料的保存是需要在SignIn進(jìn)行的,比如 Cookies Authentication 中間件就在SignIn方法里面做了Cookie的保存。

2、 AuthenticationManager 這個(gè)對象是處在 HttpContext

上下文里面的,本著面向抽象和封裝的原則,放到其里面是合適的,這樣能夠很方便的用戶對其調(diào)用。

關(guān)于 AuthenticationManager 已經(jīng)介紹完了,是不是很簡單呢?

IAuthenticationHandler

有些同學(xué)可能會(huì)問了,如果 AuthenticationManager 不提供接口的話,只是一個(gè)抽象類的話,那如果自定義認(rèn)證方法就必須繼承它,這對于開發(fā)者來說是不友好的,也違背了面向接口編程的理念。嗯,確實(shí)是這樣,那么接口來了:

public interface IAuthenticationHandler
{
  void GetDescriptions(DescribeSchemesContext context);

  Task AuthenticateAsync(AuthenticateContext context);

  Task ChallengeAsync(ChallengeContext context);

  Task SignInAsync(SignInContext context);

  Task SignOutAsync(SignOutContext context);
}

這個(gè)接口是在 AuthenticationManager 實(shí)現(xiàn)類 DefaultAuthenticationManager 中延伸出來的,所以大家不用再去看里面的源碼了,記住以后如果需要重寫認(rèn)證相關(guān)的東西,實(shí)現(xiàn)IAuthenticationHandler就可以了。

Authentication 中間件

對 IAuthenticationHandler 的初步實(shí)現(xiàn),封裝了 AuthenticationHandler 這個(gè)抽象類,把具體的核心功能都交給下游去實(shí)現(xiàn)了,下面的CookieAuthentication 中間件核心類 CookieAuthenticationHandler 就是繼承自AuthenticationHandler, 知道這么多就夠了。

CookieAuthentication 中間件

故事還要繼續(xù),奧巴馬在接到小李遞來的身份證和火車票之后,首先拿著火車票在一個(gè)二維碼機(jī)器上掃描了一下,然后又拿著身份證在一個(gè)機(jī)器上刷了一下,經(jīng)過核查,發(fā)現(xiàn)都沒有問題。于是拿起印章在上面蓋了一個(gè) “ 驗(yàn)訖 ”。

這中間都發(fā)生了什么呢?

首先,在二維碼掃描的過程,這個(gè)過程二維碼機(jī)器會(huì)解析你火車票上的二維碼,如果發(fā)現(xiàn)解析失敗,會(huì)直接響應(yīng)認(rèn)證失敗。也就是你別想進(jìn)站了。

如果解析成功,就會(huì)得到你這個(gè)票據(jù)中的信息了,然后拿到你票據(jù)里面的的當(dāng)事人信息進(jìn)行驗(yàn)證是否被列為了鐵路局黑名單中。

如果驗(yàn)證通過,則會(huì)給你頒發(fā)一個(gè)識別碼,把符合你身份的一個(gè)識別碼寫入到你的火車票中和檢票員旁邊的電腦系統(tǒng)中,即 “ 驗(yàn)訖 ”。

話說這個(gè)驗(yàn)訖有點(diǎn)高級,它會(huì)向你的火車票芯片中寫入一些信息,那么都寫入些什么信息呢? 1、奧巴馬個(gè)人的信息。2、驗(yàn)證途中的一些上下信息。3、使用的驗(yàn)證方案。

知道了,這些之后,那么就很容易實(shí)現(xiàn)這個(gè)驗(yàn)證方法了,對吧? 以下是 CookieAuthentication 中間件中的核心類 CookieAuthenticationHandler 的里面的核心方法HandleAuthenticateAsync(),同樣你可以理解為實(shí)現(xiàn)的 IAuthenticationHandler 接口的 AuthenticateAsync:

protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
  // 解析二維碼
  var result = await EnsureCookieTicket();
  if (!result.Succeeded)
  {
    return result;
  }

  // 從二維碼中拿當(dāng)事人信息進(jìn)行驗(yàn)證
  var context = new CookieValidatePrincipalContext(Context, result.Ticket, Options);
  await Options.Events.ValidatePrincipal(context);

  if (context.Principal == null)
  {
    return AuthenticateResult.Fail("No principal.");
  }

  if (context.ShouldRenew)
  {
    RequestRefresh(result.Ticket);
  }
  
  // 驗(yàn)訖, 寫入芯片
  return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme));
}

HandleSignInAsync

我們故事繼續(xù)……

奧巴馬檢票完成之后,把票就交給了小李,小李拿到票之后,導(dǎo)演又喊了一聲:“ cut ”……

怎么又停了,小李和奧巴馬一肚子的疑惑,導(dǎo)演說:“ 奧巴馬呀,你檢票員演的不錯(cuò),還是繼續(xù)扮演你的本職角色吧,演好了中午盒飯給你雙份,小李,你來演檢票員吧 ”。
 可以吃兩份盒飯了,奧巴馬聽后心里還是很開心。

“action” 導(dǎo)演喊了一聲……

奧巴馬接過票,向著車站里面的列車停車處走去,走到了列車門口要進(jìn)去的時(shí)候,又出現(xiàn)了一個(gè)人,奧巴馬知道,這個(gè)人就是做車內(nèi)乘客登記的(ps: 一般情況下,做乘客登記都是在列車行駛的過程中,在這里我們假設(shè)這個(gè)做乘客登記的人比較勤快,就在車門口守著),登記完成之后就讓奧巴馬進(jìn)去了。

那么,登記這個(gè)過程中都干了些什么呢?

首先,登記員的手持設(shè)備會(huì)解析火車票票里面寫入芯片中的信息,發(fā)現(xiàn)沒有問題,就開始向自己手里面的登記本登記信息了,主要包含車票主人信息,過期時(shí)間,審核人等。

這樣整個(gè)過程就是 HandleSignInAsync 的一個(gè)過程,換成程序術(shù)語就是,組裝 Cookie 登入上下文信息,寫入到 Http 流的 header 中,也就寫入到了客戶端瀏覽器cookie。

至此,整個(gè)過程就完了,我們來看一下代碼:

//方法里面的流程,我只列出了核心部分,影響閱讀的全刪了
protected override async Task HandleSignInAsync(SignInContext signin)
{
  // 解析芯片中的信息
  var result = await EnsureCookieTicket();
  
  // 組織登入上下文,設(shè)置過期時(shí)間等
  // 使用 data protected 加密登記本上的信息
  var cookieValue = Options.TicketDataFormat.Protect(ticket);

  // 寫入到瀏覽器header
  await ApplyHeaders(cookieValue);
}

不想深入了解的可以忽略這部分內(nèi)容:

在 HandleSignInAsync 這個(gè)函數(shù)的源碼中,其中有一個(gè)很巧妙的設(shè)計(jì), 就是 await Options.Events.SignedIn(signedInContext); 這樣一句代碼,干什么用的呢? 而且前后一共調(diào)用了兩次,有同學(xué)知道是為什么嗎? 我準(zhǔn)備在下一篇中給出答案。

還記得前面 HttpContext 中的ClaimsPrincipal User嗎? 就是小李臨時(shí)頂替的那個(gè)角色,現(xiàn)在有值了,他就是是奧巴馬了。

奧巴馬在座位上坐好之后,經(jīng)過6個(gè)小時(shí)的路程就從北京到杭州了,不得不佩服中國高鐵的速度呀,在欣賞晚西湖的風(fēng)景后,奧巴馬給我們傳來了一張照片:

如何入門ASP.NETCore中dentity

至此,CookieAuthentication 中間件的整個(gè)工作流程已經(jīng)講完了,故事也結(jié)束了。

以上,就是這兩行代碼背后的故事:

var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "奧巴馬") }, CookieAuthenticationDefaults.AuthenticationScheme));
await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI