Day 23 ASP.NET Core Identity 说明

前面有说到UserAuthentication()UserAuthorization(),这两个的差别在於:前者用於验证登入者是谁,後者则决定登入者可以做什麽。

举例来说,一个员工要登入员工系统,他必须输入帐号(如员工 ID、姓名或是 email)、密码,系统才能知道是谁登入了,这就是 Authentication(验证),处理 Authentication 的方式有 Cookie、Token、第三方验证(OAuth 或 API-token)、OpenIdSAML

而当员工登入系统後,一般员工通常不会有跨部门或是管理权限,他只能看到他自己或所属部门的资讯,例如生产部员工看不到会计部的财务,不过会计部为了计算成本却看得到生产部的原料价格,这就是 Authorization (授权)。

在决定登入者可以做什麽前,必须先知道登入者是谁,所以UserAuthentication()必须放在UserAuthorization()前面。

ASP.NET Core Identity 使用的是基於 Claim 的验证,要了解 Claim,必须先了解 Claim、ClaimsIdentity 跟 ClaimsPrincipal 是什麽。

Claim 就是关於使用者的一些资讯,Claim Type 跟 Claim Value(可以不用给)就组成一个 Claim,Claim 可以是姓名、电话、角色、Email甚至是角色等等。Authorization 就是用 Claim 判断使用者有无授权。
https://ithelp.ithome.com.tw/upload/images/20210923/20140893oWPd9NoPw6.png

ClaimsIdentity 则是多个 Claim 的集合,像是驾照上面记录了姓名、生日、电话,驾照就是一个 ClaimsIdentity。

ClaimsPrincipal 是多个 ClaimsIdentity 的集合,台湾人都有身分证跟健保卡,有些人还有驾照,身分证、健保卡跟驾照都是 ClaimsIdentity,持有它们的人就是 ClaimsPrincipal。

而每一个 HTTP request 都会产生 HttpContext 物件,该物件就存有目前 request 的资讯,其下可以找到一个型别为 ClaimsPrincipal 的 Property 名为 User,这个 Property 就是由UseAuthentication()引入的 Authentication Middleware 产生的。

登入机制可以用 Cookie 或是 JWT 实作,但 Authentication Middleware 怎麽知道要用哪个方法产生 User Property?那就要看 Authentication Scheme 跟 Authentication Handlers。

Authentication Handlers

Authentication Handlers 就是处理验证的方式,ASP.NET Core Identity 可以呼叫AuthenticateAsync()API 去验证使用者已登入,如验证失败就呼叫ChallengeAsync()将使用者导回登入页面,如授权失败则用ForbidAsync()禁止使用者访问,当然也可以自己实作这些行为。下面例子中用了 JWT 跟 Cookie 的验证方式,如果用了前者,就必须验证 JWT token 并产生 ClaimsPrincipal 回传到 HttpContext.User 中;使用後者则会检查当前 request 的 cookie并产生 ClaimsPrincipal。

   services.AddAuthentication()
      .AddJwtBearer()
      .AddCookie();

Authentication Scheme

用了任何一种方式注册 Authentication Handlers 就称为 Authentication Scheme,每个 Authentication Scheme 都有一个独特的名字以识别,且可以自己设定 Authentication Handlers,下面的程序结果跟上面会是一样,因为它们都有预设的 Scheme Name。

services.AddAuthentication()
    .AddJwtBearer("Bearer")
    .AddCookie("Cookies");

Blazor Authentication

Blazor 用的验证方式跟 ASP.NET Core 一样,不过 Blazor WebAssembly 跟 Blazor Server 又有不同,前者的验证就像任何前端网站一样可以被绕过,因为使用者端的程序可以被使用者改动,因此发送资料的 API 端一定也需要验证;後者则可用内建的 AuthenticationStateProvider 取得前面说的 HttpContext.User,笔者此前就是自己继承并覆写这项 Service 实作 JWT 验证的。

AuthenticationStateProvider 就是昨天说到的<AuthorizeView><CascadingAuthenticationState>可以取得当前验证状态的原因,但如果没有要覆写预设验证机制的话,建议不要自己在 Component 注入一个 AuthenticationStateProvider 出来,直接使用的缺点很明显,若当前 request 的验证状态有异动,因为你改动了这个 Component 的验证机制,该 Component 就不会被告知。

可以看到下图,ApiAuthenticationStateProvider继承了AuthenticationStateProvider,并覆写了Task<AuthenticationState>,这个 Property 可以取得当前的验证状态,MarkUserAsAuthenticated()MarkUserAsLoggedOut()则是笔者自己写的方法用以标示使用者通过验证及登出系统,NotifyAuthenticationStateChanged()顾名思义会通知各个 Component 当前验证状态,这就是自己继承并覆写的案例。
https://ithelp.ithome.com.tw/upload/images/20210923/201408935iHOVzFcnc.png

下图则是在 Component 取得当前 request 的 HttpContext.User 及 Claims 的作法,不过这里是先利用服务取得 User 再取得其下 Claims,其实是多此一举了。
https://ithelp.ithome.com.tw/upload/images/20210923/20140893qVp2maYa9w.png

如果只是要取得 HttpContext.User,只要如下图般就可以了,因为 Task<AuthenticationState>会以[CascadingParameter]的方式层层传递下去。
https://ithelp.ithome.com.tw/upload/images/20210923/20140893Vye11pVm90.png

Ref:Introduction to Authentication in ASP.NET Core

Ref:ASP.NET Core Blazor authentication and authorization


<<:  网路是怎样连接的(五)Socket API

>>:  EP 15: The Button of item in ListView binds Command to ViewModel

IOS、Python自学心得30天 Day-7 TensorFlow 结果预测

执行过後的结果大概是像这样 不过执行结果并不理想 不确定是否是训练样本不足 还是训练模型时的设定没有...

Day 19 BeautifulSoup模组一

接下来的几天,要跟大家介绍一个超级重要的模组—BeautifulSoup 利用它,能轻松地找到HTM...

Day 22: Behavioral patterns - Mediator

目的 当系统内的物件们各自沟通的情况日益严重时,建立一个负责沟通的集中所,让元件们不在「直接」,而是...

[Day14]C# 鸡础观念- 不同层次的阵列~二维阵列

既然空间有维度, 阵列也像是空间一样, 他是拥有维度的, 就让我们探索看看吧 二维阵列 就如同象棋棋...