日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core Identity Hands On(2)——注册、登录、Claim

發(fā)布時(shí)間:2023/12/4 asp.net 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core Identity Hands On(2)——注册、登录、Claim 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一篇文章(ASP.NET Core Identity Hands On(1)——Identity 初次體驗(yàn))中,我們初識(shí)了Identity,并且詳細(xì)分析了AspNetUsers用戶存儲(chǔ)表,這篇我們將一起學(xué)習(xí)Identity 默認(rèn)生成的樣板代碼的注冊(cè)與登陸過(guò)程

注冊(cè)/Register

打開(kāi)AccountController找到?public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)方法

這個(gè)方法切實(shí)的創(chuàng)建用戶并存儲(chǔ)到數(shù)據(jù)庫(kù),完整的過(guò)程代碼比較復(fù)雜,所以我們用一張表格來(lái)展現(xiàn)具體過(guò)程,首先看緊挨著箭頭的那一列文本,即標(biāo)題為“工作”的那一列,這是完整的順序過(guò)程,用戶創(chuàng)建即從頭走到尾。剩余的信息是幫助理解的,因?yàn)樵赗egister方法中,并沒(méi)有展現(xiàn)關(guān)鍵的內(nèi)容,我列舉出他們出現(xiàn)的位置,這樣有助于理解

在看圖片之前,我們先看一下CreateAsync代碼,這可能和你的有點(diǎn)不同,因?yàn)槲覄h除了一點(diǎn)無(wú)關(guān)緊要的東西來(lái)減少篇幅

namespace IdentityDemo.Controllers

{

? ? public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)

? ? {

? ? ? ? if (ModelState.IsValid)

? ? ? ? {

? ? ? ? ? ? var user = new ApplicationUser { UserName = model.Email, Email = model.Email };

? ? ? ? ? ? var result = await _userManager.CreateAsync(user, model.Password);

? ? ? ? ? ? if (result.Succeeded)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);

? ? ? ? ? ? ? ? var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);

? ? ? ? ? ? ? ? await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl);


? ? ? ? ? ? ? ? await _signInManager.SignInAsync(user, isPersistent: false);

? ? ? ? ? ? ? ? return RedirectToLocal(returnUrl);

? ? ? ? ? ? }

? ? ? ? ? ? AddErrors(result);

? ? ? ? }

? ? ? ? // If we got this far, something failed, redisplay form

? ? ? ? return View(model);

? ? }

如果不太理解代碼也沒(méi)關(guān)系,我們看表格

另外值得注意的是圖中的標(biāo)注①,驗(yàn)證用戶名中的字符,他的默認(rèn)值是

public string AllowedUserNameCharacters { get; set; } = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";

如果我們想更改設(shè)置怎么辦?還有表格中提到了?如果用戶支持鎖定如果要求郵件不能重復(fù),這些未確定的值從哪來(lái)的?

如果你熟悉 asp.net core ,那我猜你可能已經(jīng)想到了

沒(méi)錯(cuò)?Options?就是 Di中的 Options在起作用。

打開(kāi)項(xiàng)目根目錄的Startup.cs文件

public class Startup{ ? ?//略...public void ConfigureServices(IServiceCollection services) ? ?{ ? ? ? ?//略...services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders(); ? ? ? ?//略...} }

當(dāng)前整個(gè)identity options應(yīng)用的都是默認(rèn)配置,所以這里看不到option的蹤跡,接下來(lái)我們就以剛才提到的三個(gè)選項(xiàng)為例,修改option 的值,修改后的代碼如下

public class Startup{ ? ?//略...public void ConfigureServices(IServiceCollection services) ? ?{ ? ? ? ?//略...services.AddIdentity<ApplicationUser, IdentityRole>(options=>{options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.@";options.User.RequireUniqueEmail = false;options.Lockout.AllowedForNewUsers = false;}).AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders(); ? ? ? ?//略...} }

允許的用戶名字符由abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+變?yōu)閍bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.@?(現(xiàn)在你再試試注冊(cè),之前可以用?_?現(xiàn)在不能用了)

要求郵件不重復(fù)由true變?yōu)閒alse

允許新用戶鎖定由true變?yōu)閒alse

IdentityOptions?可配置的選項(xiàng)非常多,完整的列表請(qǐng)移步?配置 ASP.NET 核心標(biāo)識(shí)

更多關(guān)于Options的內(nèi)容請(qǐng)移步?asp.net core 文檔——配置與選項(xiàng)?一節(jié)

登陸之前——咱們得先弄清Claim

舉個(gè)例子

假設(shè)有這樣一家動(dòng)物園,這家動(dòng)物園要門票,門票要從動(dòng)物園門口的售票室買,購(gòu)買后,能得到一張紙質(zhì)的票據(jù)。紙很特殊,動(dòng)物園驗(yàn)票能通過(guò)紙張來(lái)判斷門票是不是真的,還能看出你有沒(méi)有涂改門票。門票上還有時(shí)間,指示什么時(shí)候門票到期,只要門票沒(méi)有到期,你就可以隨意進(jìn)出動(dòng)物園

嗯,這么長(zhǎng)個(gè)例子,其實(shí)和Claim沒(méi)什么關(guān)系 :)

門票上有什么?我們來(lái)假設(shè)一下

好了,我們假設(shè)的門票就這樣,從門票的第二行(姓名...)開(kāi)始,每一行都是一個(gè)Claim

有了上面的鋪墊,我們接下來(lái)正式介紹下Claim

釋義

Claim 本意有

  • vt.聲稱;索取;斷言;需要

  • vi.提出要求

  • n.索賠;聲稱;(根據(jù)權(quán)利而提出的)要求;斷言

斷言是比較準(zhǔn)確的釋義,另外可以理解成聲明,每一條claim 都代表了一條票據(jù)的信息,比如示例票據(jù)上的姓名等等。claim 的基本組成是?type和value,上面票據(jù)中左側(cè)的就是type右面就是value

在 .net core 基礎(chǔ)類庫(kù)中是含有Claim的實(shí)現(xiàn)類的,它的位置是

System.Security.Claims.Claim

我們看一個(gè)真實(shí)的claim的例子

{"sub": "1234567890","name": "John Doe","iat": 1516239022}

這個(gè)例子中含有3個(gè)claim

  • sub subject 主題,往往指Id

  • name 就是name

  • iat issue at 發(fā)出時(shí)間

這個(gè)例子中的 type 都是?JWT RFC中的標(biāo)準(zhǔn)jwt claim,上面這個(gè)例子是一個(gè)jwt票據(jù)的一部分,而在identity 中,默認(rèn)使用的是cookie 身份認(rèn)證,所以使用的不是 jwt 票據(jù),而是加密cookie票據(jù)(identity沒(méi)有這樣定義,這樣寫是為了和jwt票據(jù)區(qū)分開(kāi)),但是票據(jù)里面的內(nèi)容,jwt和 加密cookie都是一樣的都是——“claim

再回顧下 claim是什么? 就是一條一條的 type-value 鍵值對(duì),里面存儲(chǔ)了身份證明信息

而承載claim的東西就是票據(jù),票據(jù)有很多種 jwt 和cookie 都是主流,不過(guò)應(yīng)用場(chǎng)景不一樣,by the way 票據(jù)的英文名稱是“token”,你需要記住它,后續(xù)的文章中,我們會(huì)學(xué)習(xí)如何同時(shí)使用支持移動(dòng)后端驗(yàn)證(jwt token)以及僅僅使用 jwt token

登陸過(guò)程

依舊在AccountController中,我們找到public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)方法

public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)

{

? ? ? ? var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);

? ? ? ? if (result.Succeeded)

? ? ? ? {

? ? ? ? ? ? return RedirectToLocal(returnUrl);

? ? ? ? }

? ? ? ? if (result.RequiresTwoFactor)

? ? ? ? {

? ? ? ? ? ? return RedirectToAction(nameof(LoginWith2fa), new { returnUrl, model.RememberMe });

? ? ? ? }

? ? ? ? if (result.IsLockedOut)

? ? ? ? {

? ? ? ? ? ? return RedirectToAction(nameof(Lockout));

? ? ? ? }

? ? ? ? else

? ? ? ? {

? ? ? ? ? ? ModelState.AddModelError(string.Empty, "Invalid login attempt.");

? ? ? ? ? ? return View(model);

? ? ? ? }

? ??

}

這是個(gè)簡(jiǎn)略版本的代碼,只保留了關(guān)鍵信息

用于登陸的代碼只有一行var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);但里面做的事情可是非常多的,我們稍后在講,現(xiàn)在我們先要了解一下,登陸之后有哪些結(jié)果產(chǎn)生——result

SignInResult

SignInResult 只有5個(gè)屬性

  • Success 表示一切順利,登陸成功

  • Failed 登陸失敗

  • LockedOut 用戶被鎖定了

  • NotAllowed 不允許登陸

  • TwoFactorRequired 要求雙因子驗(yàn)證

然后我們看一下具體的登陸過(guò)程,這里仍舊是一個(gè)表格,

登陸過(guò)程描述

代碼范圍作用
我們的代碼
從用戶輸入獲取用戶名、密碼、記住我
Identity檢查是否需要確認(rèn)郵件以及此用戶郵件是否已經(jīng)確認(rèn)
檢查是否支持鎖定用戶以及此用戶是否已被鎖定
檢查用戶密碼是否正確,以及是否需要升級(jí)①
如果支持鎖定用戶,并且支持在登陸失敗超過(guò)指定次數(shù)鎖定用戶則增加AccessFailedCount計(jì)數(shù),并且在到達(dá)設(shè)置的計(jì)數(shù)上限后清零計(jì)數(shù)設(shè)置LockoutEnd時(shí)間②
通過(guò)用戶的基本信息生成Claims 及ClaimsIdentity③
如果支持額外的Claims存儲(chǔ)則添加額外的Claims④
【注:Identity支持,額外的Claims存儲(chǔ)在AspNetUserClaims表中】
生成ClaimsPrinciple⑤
添加認(rèn)證方法Claim⑥
HttpAbstractions確保上一個(gè)單元格中的認(rèn)證方法不是空
通過(guò)認(rèn)證方法,獲取指定的IAuthenticationSignInHandler實(shí)例⑦
Security使用ClaimsPrinciple創(chuàng)建 票據(jù)
加密票據(jù)
將加密后的票據(jù)添加到http響應(yīng)的cookie頭中

上表就是登陸過(guò)程,Identity默認(rèn)使用cookie作為 claims 的載體,在最后的步驟中將含有claims的票據(jù)加密存儲(chǔ)到cookie中,這樣在登陸之后再次訪問(wèn)就可以驗(yàn)證cookie來(lái)識(shí)別當(dāng)前是否有用戶登錄,以及登陸用戶的身份

代碼范圍一列中,我們看到有4列,這和注冊(cè)過(guò)程中相比,多出了 HttpAbstractions 和 Security,我們先來(lái)解釋下這兩個(gè)東西是什么

HttpAbstractions*

這是 asp.net core 中的http基礎(chǔ)相關(guān)抽象,例如HttpRequest、HttpResponse、HttpContext等等
關(guān)于 HttpAbstractions的更多信息,可以訪問(wèn)它的GitHub主頁(yè)?https://github.com/aspnet/HttpAbstractions

Security*

這個(gè)庫(kù)里面主要包含用于web開(kāi)發(fā)的安全與授權(quán)相關(guān)的中間件,在上表中 的標(biāo)注⑦IAuthenticationSignInHandler的實(shí)例,事實(shí)上就是CookieAuthenticationHandler,在后續(xù)的文章里當(dāng)我么講到身份認(rèn)證過(guò)程的時(shí)候會(huì)詳細(xì)講述身份認(rèn)證中間件及handler是如何工作的

另外,還可以訪問(wèn)他的GitHub主頁(yè)獲得更多信息https://github.com/aspnet/Security

接下來(lái)我們解釋一下上表中的標(biāo)注

標(biāo)注解釋

①檢查用戶密碼是否正確,以及是否需要升級(jí)

在ASP.NET Core Identity Hands On(1)——Identity 初次體驗(yàn)?中,我們有提到 Identity的密碼哈希有兩個(gè)版本 v2和v3,那么如果一個(gè)舊的Identity升級(jí)到新的Identity那么密碼會(huì)不兼容,所以在Identity中密碼驗(yàn)證為了兼容舊版,做了一些特殊處理。v3的密碼byte以0x01開(kāi)頭,而v2以0x00開(kāi)頭,從這里可以判斷出密碼哈希是哪個(gè)版本的然后根據(jù)不同的版本來(lái)驗(yàn)證密碼,密碼驗(yàn)證有3個(gè)結(jié)果——失敗、成功、成功且需要更新版本:

namespace Microsoft.AspNetCore.Identity{ ? ?public enum PasswordVerificationResult{Failed = 0,Success = 1,SuccessRehashNeeded = 2略...

當(dāng)驗(yàn)證結(jié)果是SuccessRehashNeeded時(shí),就會(huì)重新計(jì)算新的密碼Hash存入數(shù)據(jù)庫(kù),從而完成密碼的兼容升級(jí)

②AccessFailedCount計(jì)數(shù)、LockoutEnd時(shí)間

ASP.NET Core Identity Hands On(1)——Identity 初次體驗(yàn)中有講解

Claim、IIdentity+ClaimsIdentity、IPrincipal+ClaimsPrincipal

在過(guò)去的asp.net mvc 以及現(xiàn)在的新的 asp.net mvc core中,HttpContext都有個(gè)User屬性,可能很多開(kāi)發(fā)者都沒(méi)有使用過(guò)它

namespace Microsoft.AspNetCore.Http{ ?
?
? ??public abstract class HttpContext{ ? ? ?
? ?? ??public abstract ClaimsPrincipal User { get; set; } ? ? ? ?

所以,你暫時(shí)將ClaimsPrincipal理解成User就可以,而ClaimsPrincipal中有兩個(gè)重要的屬性

namespace System.Security.Claimspublic class ClaimsPrincipal : IPrincipal{ ? ?
? ? ? ?public virtual IEnumerable<ClaimsIdentity> Identities { get; } ?
? ? ? ?
? ? ? ?public virtual IIdentity Identity { get; }

Identities是這個(gè)Principal(user)擁有的所有Identity,Identity 是這個(gè)Principal(user)擁有的最重要的Identity,而這個(gè)Identity的實(shí)際類型是ClaimsIdentity,這里就相當(dāng)于Principal是用戶,而Identity是用戶的身份證,身份證里面記錄的是這個(gè)用戶的個(gè)人信息,也就是claims

namespace System.Security.Claims{
? ?public class ClaimsIdentity : IIdentity{ ? ?
? ? ? ? ??public virtual IEnumerable<Claim> Claims { get; }

再看一下上面的三小段代碼,你應(yīng)該就能理解 Principal、Identity、Claim的關(guān)系了

③通過(guò)用戶的基本信息生成Claims 及ClaimsIdentity

在這個(gè)步驟中大部分claims都被加入到 ClaimsIdentity中,如下所示(|右側(cè)是該claim的type)

  • UserName |http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier

  • UserId|http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name

  • SecurityStamp(如果支持的話)|AspNet.Identity.SecurityStamp

  • 存儲(chǔ)在數(shù)據(jù)庫(kù)中的額外Claims(如果支持的話)

這里的 claim 的type 是url,還有字符串,而之前提到的都是縮寫,這是不是很令人疑惑呢?

原因是 并沒(méi)有什么規(guī)定type是什么的標(biāo)準(zhǔn),我們也可以自定義type,type的意義在于發(fā)放票據(jù)的一方和驗(yàn)證票據(jù)的一方知道是什么意思就可以了,所以,如上

④額外的claims 以及 AspNetUserClaims 表

現(xiàn)在我們 就來(lái)解析一下我們的第二張表 AspNetUserClaims

這張表相對(duì)就比較簡(jiǎn)單,這張表就是用于存儲(chǔ)額外的屬于用的claim的

其中Id是int類型,這有別于User表中Id是varchar(450)要注意一下

我們來(lái)假設(shè)一個(gè)場(chǎng)景

假設(shè)我們的網(wǎng)站有一個(gè)特殊的設(shè)置,就是在用戶是男性的時(shí)候,顯示一個(gè)短發(fā)logo是女性時(shí)顯示一個(gè)長(zhǎng)發(fā)logo,我們有很多方法實(shí)現(xiàn),如果用claim實(shí)現(xiàn)的話就是相對(duì)簡(jiǎn)單的,我們將性別的的type定義為 gender, value定義為 1、2,那么在用戶創(chuàng)建時(shí)或者創(chuàng)建后,為用戶創(chuàng)建一條claim數(shù)據(jù),假設(shè)用戶是女性:

Id ? ? ? ? ?:10011ClaimType ? :genderClaimValue ?:2UserId ? ? ?:071d2a6e-ac2e-4db6-8941-372a3991b912q

當(dāng)這位用戶登錄時(shí),就會(huì)將這條數(shù)據(jù)加入到cookie票據(jù)中,成為其中的一條claim,而在用戶后續(xù)的訪問(wèn)中,我們直接從cookie中拿到票據(jù),并看到票據(jù)上寫了,這為用戶是一位女性,然后為其顯示一個(gè)長(zhǎng)發(fā)logo

⑤生成ClaimPrincipal

這是一個(gè)一步的操作

CalimsIdentity id = await GenerateClaimsAsync(user);return new ClaimsPrincipal(id);

就像我們把A用戶的身份證交到了A的手中,然后把A交還給了調(diào)用方,這很好理解

⑥添加認(rèn)證方法Claim

Principal.Identities.First().AddClaim(new Claim(ClaimTypes.AuthenticationMethod, authenticationMethod));

這一步是將使用的認(rèn)證方法添加到了 Identity中,它的type 是

http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod

不過(guò)登陸過(guò)程中,這個(gè)值是null,所以他沒(méi)有真的添加到Identity中

⑥ 和⑦

在表格中我們能看到⑥ 和⑦的范圍已經(jīng)不再Identity里了,所以Identity的任務(wù)已經(jīng)結(jié)束了,Identity就把用戶Principal做好,身份證Identity做好,身份證上的信息Claim填好,就結(jié)束了。接下來(lái)選擇哪個(gè)用于用戶登錄的handler,handler怎么做才能讓用戶登錄,Identity就不知道了,因?yàn)镮dentity是成員系統(tǒng),而用戶登錄屬于web框架,舉一個(gè)反例,不用Identity就不能使用cookie登陸了嗎?答案顯然不是的,所以成員系統(tǒng)知道用戶是誰(shuí),將用戶信息做成一個(gè)票據(jù),交給web框架

離開(kāi) Identity之后第一件事就是確保上一個(gè)單元格中的認(rèn)證方法不是空,可是剛剛明明說(shuō)了,它是null

沒(méi)錯(cuò)當(dāng)它是null 的時(shí)候,會(huì)去尋找默認(rèn)的authentication schema(這是認(rèn)證方法的另一個(gè)名字),在startup 類中,注冊(cè)Identity的服務(wù)時(shí),Identity還注冊(cè)了cookie authentication handler 順便還添加了 默認(rèn)的 authentication scheme 我們看一個(gè)精簡(jiǎn)版的代碼片段

public static IdentityBuilder AddIdentity<TUser, TRole>(略...) {services.AddAuthentication(options =>{ ? ? ? ?// 略...options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;}).AddCookie(IdentityConstants.ApplicationScheme, o =>{ ? ? ? ?// 略...})

ApplicationScheme的切實(shí)的默認(rèn)值是Identity.Application,如果你不太能理解這一小節(jié)的內(nèi)容,沒(méi)關(guān)系,你只需要知道表格中做了什么事就可以,關(guān)于 身份認(rèn)證 authentication 是個(gè)不算簡(jiǎn)單的過(guò)程,后續(xù)會(huì)撰文專門講解

最后就是加密和將cookie寫入http響應(yīng)了,這段就不展開(kāi)講了,就是一些基本操錯(cuò),而加密過(guò)程和配置 密鑰,后面會(huì)有單獨(dú)的講解章節(jié)

原文地址:?

https://www.cnblogs.com/rocketRobin/p/9077523.html


.NET社區(qū)新聞,深度好文,歡迎訪問(wèn)公眾號(hào)文章匯總 http://www.csharpkit.com

總結(jié)

以上是生活随笔為你收集整理的ASP.NET Core Identity Hands On(2)——注册、登录、Claim的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。