1. 程式人生 > >ASP.NET Core 之 Identity 入門(一)

ASP.NET Core 之 Identity 入門(一)

前言

在 ASP.NET Core 中,仍然沿用了 ASP.NET裡面的 Identity 元件庫,負責對使用者的身份進行認證,總體來說的話,沒有MVC 5 裡面那麼複雜,因為在MVC 5裡面引入了OWIN的東西,所以很多初學者在學習來很費勁,對於 Identity 都是一頭霧水,包括我也是,曾經在學 identity 這個東西前後花了一個多月來搞懂裡面的原理。所以大部分開發者對於 Identity 並沒有愛,也並沒有使用它,會覺得被綁架。

值得慶幸的是,在 ASP.NET Core 中,由於對模組的抽象化逐漸清晰,以及中介軟體的使用,這使得 Identity 的學習和使用路線變得更加平易近人,下面就讓我們一起來看看吧。

Getting Started

在開始之前,讓我們先忘記它和Entity Framework的關係,也忘記它和Authentication的關係,我們先學習幾個英語單詞。

有這麼幾個“單詞”你可能需要弄明白:

# 1: Claims

大家應該都知道身份證長什麼樣子的,如下:

其中,姓名:奧巴馬;性別:男;民族:肯亞;出生:1961.08.04,等等這些身份資訊,可以看出都是一個一個的鍵值對,那如果我們想在程式中存這些東西,怎麼樣來設計呢?對,你可能想到了使用一個字典進行儲存,一個Key,一個Value剛好滿足需求。但是Key,Value的話感覺不太友好,不太面向物件,所以如果我們做成一個物件的話,是不是更好一些呢?最起碼你可以用vs的智慧提示了吧,我們修改一下,改成下面這樣:

//我給物件取一個名字叫`Claim`你沒有意見吧
public class Claim
{
    public string ClaimType { get; set; }

    public string ClaimValue { get; set; }
}

ClaimType 就是Key,ClaimValue就代表一個Value。這樣的話,剛好可以儲存一個鍵值對。這時候姓名:奧巴馬是不是可以存進去了。

微軟的人很貼心,給我們準備了一些預設的ClaimType呢?很多常用的都在裡面呢,一起看看吧:

這裡延伸第一個知識點:ClaimTypes

為了閱讀體驗,截圖我只放了一部分哦。可以看到有什麼Name,Email,Gender,MobilePhone等常用的都已經有了,其他的還有很多。細心的讀者可能注意了,它的名稱空間是System.Security.Claims

,那就說明這個東西是.net 框架的一部分,嗯,我們暫時只需要知道這麼多就OK了。

Claim 介紹完畢,是不是很簡單,其他地方怎麼翻譯我不管,在本篇文章裡面,它叫 “證件單元”。

# 2: ClaimsIdentity

在有了“證件單元”之後,我們就用它可以製造一張身份證了,那麼應該怎麼樣製造呢?有些同學可能已經想到了,對,就是新建一個物件,然後在建構函式裡面把身份證單元傳輸進去,然後就得到一張身份證了。我們給這張身份證取一個英文名字叫 “ClaimsIdentity”,這個名字看起來還蠻符合的,既有 Claims 表示其組成部分,又有表示其用途的 Identity(身份),很滿意的一個名字。

實際上,在現實生活中,我們的身份證有一部分資訊是隱藏的,有一部分是可以直接看到的。比如新一代的身份證裡面儲存了你的指紋資訊你是看不到的,這些都儲存在身份證裡面的晶片中,那能看到的比如姓名啊,年齡啊等。我們在設計一個物件的時候也是一樣,需要暴露出來一些東西,那這裡我們的 ClaimsIdentity 就暴露出來一個 Name,Lable等。

我們造的身份證(ClaimsIdentity)還有一個重要的屬性就是型別(AuthenticationType),等等,AuthenticationType是什麼東西?看起來有點眼熟的樣子。我們知道我們自己的身份證是幹嘛的吧,就是用來證明我們的身份的,在你證明身份出示它的時候,其實它有很多種形式載體的,什麼意思呢?比如你可以直接拿出實體形式的身份證,那也可以是紙張形式的影印件,也可以是電子形式的電子碼等等,這個時候就需要有一個能夠表示其存在形式的型別欄位,對,這個AuthenticationType就是幹這個事情的。

然後我們在給我們的身份證新增一些潤色,讓其看起來好看,比如提供一些方法新增 Claims 的,刪除 Claims的,寫到二進位制流裡面的啊等等,最終我們的身份證物件看起來基本上是這樣了:

public class ClaimsIdentity
{
    public ClaimsIdentity(IEnumerable<Claim> claims){}
    
    //名字這麼重要,當然不能讓別人隨便改啊,所以我不許 set,除了我兒子跟我姓,所以是 virtual 的
    public virtual string Name { get; }
    public string Label { get; set; }
    
    //這是我的證件型別,也很重要,同樣不許 set
    public virtual string AuthenticationType { get; }
    
    public virtual void AddClaim(Claim claim);
    
    public virtual void RemoveClaim(Claim claim);
    
    public virtual void FindClaim(Claim claim);
}

嗯,到這裡,我們的身份證看起來似乎很完美了,但是從面向物件的角度來說好像還少了點什麼東西? 對~,還是抽象,我們需要抽象出來一個介面來進行一些約束,約束什麼呢?既然作為一個證件,那麼肯定會涉及到這幾個屬性資訊:
1、名字。2、型別。3、證件是否合法。
反應到接口裡面的話就是如下,我們給介面取個名字叫:“身份(IIdentity)”:

這裡延伸第二個知識點:IIdentity介面。

// 定義證件物件的基本功能。
public interface IIdentity
{
    //證件名稱
    string Name { get; }
    
    // 用於標識證件的載體型別。
    string AuthenticationType { get; }
    
    //是否是合法的證件。
    bool IsAuthenticated { get; }
}

所以我們的 ClaimsIdentity 最終看起來定義就是這樣的了:

public class ClaimsIdentity : IIdentity
{
    //......
}

ClaimsIdentity 介紹完畢,是不是發現也很簡單,其他地方怎麼翻譯我不管,在本篇文章裡面,它叫 “身份證”。

# 3: ClaimsPrincipal

有了身份證,我們就能證明我就是我了,有些時候一個人有很多張身份證,你猜這個人是幹嘛的? 對,不是黃牛就是詐騙犯。

但是,有些時候一個人還有其他很多種身份,你猜這個人是幹嘛的?這就很正常了對不對,比如你可以同時是一名教師,母親,商人。如果你想證明你同時有這幾種身份的時候,你可能需要出示教師證,你孩子的出生證,法人代表的營業執照證。

在程式中,一個身份證不僅僅代表你這個人了,而是代表一個身份,是證明你自己的主要身份哦。如果一個人還有其他很多種身份,這個時候就需要有一個東西(載體)來攜帶著這些證件了對吧?OK,我們給需要攜帶證件的這個物件取一個貼切點的名字,叫“證件當事人(ClaimsPrincipal)”吧。

以下是 Principal 這個單詞在詞典給出的解釋,我用它你應該沒意見吧:

principal  ['prɪnsəpl]  
adj. 主要的;資本的
n. 首長;校長;資本;當事人

這個時候可能有同學會問了,是不是應該叫ClaimsIdentityPrincipal比較好呢?嗯,我也覺得應該叫 ClaimsIdentityPrincipal 可能更好一點,或許微軟的人偷懶了,簡寫成了ClaimsPrincipal

知道其功能後,程式碼就很好寫了,和上面ClaimsIdentity一樣的套路:

public class ClaimsPrincipal 
{
    //把擁有的證件都給當事人
    public ClaimsPrincipal(IEnumerable<ClaimsIdentity> identities){}
    
    //當事人的主身份呢
    public virtual IIdentity Identity { get; }
    
    public virtual IEnumerable<ClaimsIdentity> Identities { get; }
    
    public virtual void AddIdentity(ClaimsIdentity identity);
    
    //為什麼沒有RemoveIdentity , 留給大家思考吧?
}

當時人看起來也幾乎完美了,但是我們還需要對其抽象一下,抽象哪些東西呢? 作為一個當事人,你應該有一個主身份吧,就是你的身份證咯,可能你還會用到角色(角色後面會詳細介紹,這裡你知道有這麼個東西就行了)。

這裡延伸第三個知識點:IPrincipal 介面。

public interface IPrincipal
{
    //身份
    IIdentity Identity { get; }
    
    //在否屬於某個角色
    bool IsInRole(string role);
}

然後,我們的 證件當事人 看起來應該是這樣的:

public class ClaimsPrincipal : IPrincipal 
{
   //...
}

ClaimsPrincipal 介紹完了,也很簡單吧? 其他地方怎麼翻譯我不管,在本篇文章裡面,它叫 “證件當事人”。

想在,我們已經知道了 “證件單元(Claims)” , “身份證(ClaimsIdentity)” , “證件當事人(ClaimsPrincipal)”,並且整理清楚了他們之間的邏輯關係,趁熱打鐵,下面這個圖是一個identity登入部分的不完全示意圖,虛線圈出來的部分應該可以看懂了吧:

可以看出,首先我們在app這邊有一些證件單元,然後呼叫ClaimsIdentity把證件單元初始化為一個身份證,然後再把身份證交給證件當事人由其保管。

才把 Getting Started 寫完,發現已經這麼長了,所以打算寫成一個系列了,可能3 - 4篇吧。

總結

好了,本篇就先介紹到這裡,在本篇部落格中,我們學會了幾個英文單詞,並且知道了這些英文單詞在程式中是扮演這怎麼樣一個物件。並且根據圖我們知道了這些物件在整個認證系統種處在怎麼樣一個位置。 我發現如果想把 identity 講清楚僅僅靠這一篇部落格是不夠的,下一篇我們將對.NET Authentication中介軟體進行抽絲剝繭,直到掌握.NET的整個認證系統後,我們再來看一下 Identiy 到底和 Entity Framework 有著怎樣的愛恨情仇。

這僅僅是一個開始,大家如果覺得本篇部落格對您有幫助的話,感謝您的【推薦】,如果你對 .NET Core 感興趣可以關注我,我會定期在部落格分享關於 .NET Core 的學習心得。

相關推薦

ASP.NET Core Identity 入門

前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET裡面的 Identity 元件庫,負責對使用者的身份進行認證,總體來說的話,沒有MVC 5 裡面那麼複雜,因為在MVC 5裡面引入了OWIN的東西,所以很多初學者在學習來很費勁,對於 Identity 都是一頭霧水,包括我也是,曾經在學 ide

ASP.NET Core Identity 入門

前言 在 上篇文章 中講了關於 Identity 需要了解的單詞以及相對應的幾個知識點,並且知道了Identity處在整個登入流程中的位置,本篇主要是在 .NET 整個認證系統中比較重要的一個環節,就是 認證(Authentication),因為想要把 Identity 講清楚,是繞不過 Authentica

.NET Core單元測試入門

目錄 什麼是單元測試 .NET Core中的測試框架 一個最基礎的單元測試 我們再看看上面的程式碼 什麼是單元測試 單元測試是對軟體中的最小可測試單元進行檢查和驗證。對於單元測試

asp.net core 擁抱 docker 技術 概覽

測試 docker 架構 swa ima 進程 基於 概念 registry 這是一個huge 坑慢慢填吧。這裏只是一個目錄 或總覽。 docker 是什麽? docker可以看做一種虛擬機技術,但沒有傳統虛擬機那麽復雜,是基於進程的虛擬,就是讓一個一個進程,認為自己處於一

反向教學系列——PHP入門

water oui 版本 名稱 令行 完全 技術 地址 安裝目錄 php是什麽?其實就是html的功能加強版。網頁本來在服務器上,如果客戶端問服務器索取網頁文件(xxx.html),那麽服務器就會把客戶端指定的網頁發回去。(根據我的理解,)php是因“表單”而誕生的,所謂表

反向教學系列——Django入門【不需知道web框架】

Django 教程 反向教學 一派胡言 用這東西最終是建網站的,或者是更一般意義的服務器。服務器麽,就是如果用別的電腦(“客戶機”)給它發請求,它會返回一些東西——如果給隨便某個機器發信息,它自然未必理你。要想某機器回應你,得滿足這些條件——它不處在關機狀態它能收到你的信息,你也能收到它的信息

ASP.NET Core 2 學習筆記視圖

部分 合成 cati 分享 col script text var AC ASP.NET Core MVC中的Views是負責網頁顯示,將數據一並渲染至UI包含HTML、CSS等。並能痛過Razor語法在*.cshtml中寫渲染畫面的程序邏輯。本篇將介紹ASP.NET Co

ASP.NET Core 2 學習筆記依賴註入

pub framework 三次 DDM order 包裝 差異 限制 cto 原文:ASP.NET Core 2 學習筆記(四)依賴註入ASP.NET Core使用了大量的依賴註入(Dependency Injection, DI),把控制反轉(Inversion Of

ASP.NET Core 2 學習筆記生命周期

RF Go 使用 HR runt block top 最大的 env 原文:ASP.NET Core 2 學習筆記(二)生命周期要了解程序的運行原理,就要先知道程序的進入點及生命周期。以往ASP.NET MVC的啟動方式,是繼承 HttpApplication 作為網站開始

ASP.NET Core 2 學習筆記路由

local quest urn AD term 執行 自動 routes code 原文:ASP.NET Core 2 學習筆記(七)路由ASP.NET Core通過路由(Routing)設定,將定義的URL規則找到相對應行為;當使用者Request的URL滿足特定規則條件

ASP.NET Core 2 學習筆記MVC

方便 web redirect AR return his 架構模式 PE ofo 原文:ASP.NET Core 2 學習筆記(六)MVC ASP.NET Core MVC跟ASP.NET MVC觀念是一致的,使用上也沒有什麽太大的變化。之前的ASP.NET MVC把MV

ASP.NET Core 配置跨域CORS

tin sha har exce pub header service 策略 uil 1.安裝程序CORS程序包 Install-Package Microsoft.AspNetCore.Mvc.Cors 一般默認都帶了此程序包的 2.配置CORS服務 在 Startu

ASP.NET Core 專案配置 ( Startup )轉載

原文:https://www.twle.cn/l/yufei/aspnetcore/dotnet-aspnet-startup.html 由於是個人網站,怕沒了,特意複製儲存,個人覺得講的非常透徹   前面幾章節中我們已經介紹和使用過 Startup 類

ASP.NET Core AD 域登入 轉載

在選擇AD登入時,其實可以直接選擇 Windows 授權,不過因為有些網站需要的是LDAP獲取資訊進行授權,而非直接依賴Web Server自帶的Windows 授權功能。   當然如果使用的是Azure AD/企業賬號登入時,直接在ASP.NET Core建立專案時選擇就好了。來個ABC:1.

asp.net core 2.1 dotnetEF.core Dbfirst 生成 檢視與呼叫儲存過程

1 檢視,可以直接在 Model中寫 檢視的模型 執行方式如找到一個,還沒有試過:     有關 .net core EF 的問題有一個地址: https://github.com/aspnet/EntityFra

.net跨平臺mono應用——Linux系統初識

前言:最近因專案需要,開始研究.net應用的跨平臺開發。主要需求是將windows上的窗體應用在.net上部署。因為Linux系統上不支援Winform。因此暫定的解決方案是Mono+GTK#。因為在這之前我完全沒有接觸過Linux系統,也未曾瞭解過Mon

asp.net core 2.1 dotnet

呼叫  ET 的方式 新建 APPDbContext 這樣一個檔案: using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Mi

Vue旅-----入門

第一步:從官方的vue教程開始學起 官網:https://cn.vuejs.org(自己也可去看著文件去學) 希望你html,css,js有一定的基礎,再去學它,要不然很費勁。 什麼是vue? 1.官方的讀法是:Vue (讀音 /vjuː/,類似於 view

Python編寫簡單爬蟲新手入門

最近學習了一下python的基礎知識,大家一般對“爬蟲”這個詞,一聽就比較熟悉,都知道是爬一些網站上的資料,然後做一些操作整理,得到人們想要的資料,但是怎麼寫一個爬蟲程式程式碼呢?相信很多人是不會的,今天寫一個針對新手入門想要學習爬蟲的文章,希望對想要學習的你能有所幫助~~廢

asp.net core 2.1 dotnetEF.core DBFisrt生成模型類

工具的scaffold-dbcontext(資料庫上下文腳手架)指令來生成models和context。 指令詳細介紹: Scaffold-DbContext [-Connection] <String> [-Provider] <String>