主頁 > .NET開發 > 【asp.net core 系列】15 自定義Identity

【asp.net core 系列】15 自定義Identity

2020-09-11 17:19:25 .NET開發

0. 前言

在之前的文章中簡單介紹了一下asp.net core中的Identity,這篇文章將繼續針對Identity進行進一步的展開,

1. 給Identity添加額外的資訊

在《【asp.net core 系列】13 Identity 身份驗證入門》一文中,我們大概了解了如何使用Identity,以及如何保存一些資訊以便后續的驗證,這里我們將深入討論一下如何給Identity添加更多的資訊,

我們知道在給Identity添加資料的時候,需要添加一個Claim物件,我們先回顧一下Claim的資訊,Claim的屬性大多只提供了公開的get訪問器,所以這個類的重點在于構造方法:

public class Claim
{
    // 基礎的
    public Claim(string type, string value);
    public Claim(string type, string value, string valueType);
    public Claim(string type, string value, string valueType, string issuer);
    public Claim(string type, string value, string valueType, string issuer, string originalIssuer);
    //
    public Claim(BinaryReader reader);
    public Claim(BinaryReader reader, ClaimsIdentity subject);
}

暫且看一下幾個使用字符型別的建構式引數:

  1. type Claim的型別,支持自定義,但asp.net core 提供了一個基礎的型別定義:
public static class ClaimTypes
{
    // 隱藏其他屬性
    public const string Name = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name";
    public const string Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
}

? 這個類里定義了大多數情況下會用到的Claims的型別,

  1. value 存放Claim的值,通常情況下不對這個值進行約束

  2. valueType 表示 value的型別,取值范圍參考類:

    public static class ClaimValueTypes
    {
        public const string Base64Binary = "http://www.w3.org/2001/XMLSchema#base64Binary";
        public const string UpnName = "http://schemas.xmlsoap.org/claims/UPN";
        public const string UpnName = "http://schemas.xmlsoap.org/claims/UPN";
     	public const string UInteger32 = "http://www.w3.org/2001/XMLSchema#uinteger32";
        public const string Time = "http://www.w3.org/2001/XMLSchema#time";
        public const string String = "http://www.w3.org/2001/XMLSchema#string";
        public const string Sid = "http://www.w3.org/2001/XMLSchema#sid";
        public const string RsaKeyValue = https://www.cnblogs.com/c7jie/p/"http://www.w3.org/2000/09/xmldsig#RSAKeyValue";
        public const string Rsa = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/rsa";
        public const string Rfc822Name = "urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name";
        public const string KeyInfo = "http://www.w3.org/2000/09/xmldsig#KeyInfo";
        public const string Integer64 = "http://www.w3.org/2001/XMLSchema#integer64";
        public const string X500Name = "urn:oasis:names:tc:xacml:1.0:data-type:x500Name";
        public const string Integer32 = "http://www.w3.org/2001/XMLSchema#integer32";
        public const string HexBinary = "http://www.w3.org/2001/XMLSchema#hexBinary";
        public const string Fqbn = "http://www.w3.org/2001/XMLSchema#fqbn";
        public const string Email = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress";
        public const string DsaKeyValue = "http://www.w3.org/2000/09/xmldsig#DSAKeyValue";
        public const string Double = "http://www.w3.org/2001/XMLSchema#double";
        public const string DnsName = "http://schemas.xmlsoap.org/claims/dns";
        public const string DaytimeDuration = "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#dayTimeDuration";
        public const string DateTime = "http://www.w3.org/2001/XMLSchema#dateTime";
        public const string Date = "http://www.w3.org/2001/XMLSchema#date";
        public const string Boolean = "http://www.w3.org/2001/XMLSchema#boolean";
        public const string Base64Octet = "http://www.w3.org/2001/XMLSchema#base64Octet";
        public const string Integer = "http://www.w3.org/2001/XMLSchema#integer";
        public const string YearMonthDuration = "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#yearMonthDuration";
    }
    
  3. issuer 用來存放 Claim的發布者,默認值是:ClaimsIdentity.DefaultIssuer 該值允許在建構式是傳NULL,一旦傳NULL,則自動認為是ClaimsIdentity.DefaultIssuer

  4. originalIssuer Claim的原發布人,如果不給值,則默認與issuer一致,

這是從建構式以及相關檔案中獲取到的,

關于ClaimTypes里我只貼了兩個,原因是這兩個值在Claim中是兩個必不可少的值,根據屬性名就能看出來,一個是設定用戶的名稱,一個是設定用戶的角色,

那么,繼續探索Claim里的屬性和方法:

public class Claim
{
    public string Type { get; }
    public ClaimsIdentity Subject { get; }
    public IDictionary<string, string> Properties { get; }
    public string OriginalIssuer { get; }
    public string Issuer { get; }
    public string ValueType { get; }
    public string Value { get; }
    public virtual Claim Clone();
    public virtual Claim Clone(ClaimsIdentity identity);
    public virtual void WriteTo(BinaryWriter writer);
}

幾個基本屬性都是從建構式中獲取的,這里就不做過多的介紹了,不過值得注意的一點是,Properties這個屬性的值獲取是需要使用

public Claim(BinaryReader reader, ClaimsIdentity? subject)

這個構造方法才可以有效的對其進行賦值,所以這個屬性并沒有太多值得關注的地方,

介紹完了Claim類之后,我們繼續看一下Identity相關的常用類:

public class ClaimsIdentity : IIdentity;

通過這個類的宣告,我們可以看出它實作了介面:

public interface IIdentity
{
    string? AuthenticationType { get; }
    bool IsAuthenticated { get; }
    string? Name { get; }
}

其中

  • AuthenticationType 表示驗證型別
  • IsAuthenticated 表示是否驗證通過
  • Name 存放的用戶名

這是Identity里最關鍵的三個屬性,貫穿著整個Identity體系,我們繼續看一下ClaimsIdentity的幾個關鍵點:

public class ClaimsIdentity : IIdentity
{
    public ClaimsIdentity(string authenticationType);
    public ClaimsIdentity(IIdentity identity);
    public ClaimsIdentity(IEnumerable<Claim> claims);
    public ClaimsIdentity(IEnumerable<Claim> claims, string authenticationType);
    public ClaimsIdentity(IIdentity identity, IEnumerable<Claim> claims);
    public virtual void AddClaim(Claim claim);
    public virtual void AddClaims(IEnumerable<Claim> claims);
}

對于ClaimsIdentity而言,其核心內容是Claim實體,我們通常需要構造Claim物件,在Claim物件中添加我們想添加的值,然后裝入ClaimIdentity中,這里有一個值需要額外注意一下:AuthenticationType 表示驗證型別,值并沒有額外要求,不過對于使用Cookie作為資訊保存的話,需要設定值為:

CookieAuthenticationDefaults.AuthenticationScheme

這時候,我們已經獲得了一個Identity物件,在asp.net core 中 Identity體系還有最后一個關鍵類:

public class ClaimsPrincipal : IPrincipal
{
    public ClaimsPrincipal();
    public ClaimsPrincipal(IIdentity identity);
    public ClaimsPrincipal(IPrincipal principal);
    public virtual void AddIdentities(IEnumerable<ClaimsIdentity> identities);
    public virtual void AddIdentity(ClaimsIdentity identity);
}

這個類提供了幾個方法用來存盤Identity,這個類在IPrincipal基礎上以Identity為基礎資料,這一點可以通過建構式和它提供的一些方法可以確認,

2. 讀取Identity的資訊

在第一小節中,我簡單介紹了一下如何利用Claim和ClaimsIdentity以及ClaimsPrincipal這三個類來存盤用戶資訊以及我們想要的資料,這里我們看一下如何通過Principal讀取資訊,以及簡單剖析一下背后的邏輯,

我們使用HttpContext的擴展方法:

public static Task SignInAsync(this HttpContext context, ClaimsPrincipal principal);

將我們設定的principal資料保存,所保存的地方取決于我們在Startup.cs中的設定,在該系列中,我們啟用了Cookie,所以這個資訊會以Cookie的形式保存,

在控制器內部時,Controller類為我們提供了一個屬性:

public ClaimsPrincipal User { get; }

通過這個屬性可以反向獲取到我們保存的Principal實體,

接下來,讓我們反向決議出Principal里面的資料:

public interface IPrincipal
{
    IIdentity? Identity { get; }
    bool IsInRole(string role);
}

IPrincipal提供了兩個基礎資料和方法,一個是獲取一個Identity物件,一個是判斷是否是某個角色,

2.1 Identity

在ClaimPrincipal中,Identity屬性的默認取值邏輯是:

if (identities == null)
{
    throw new ArgumentNullException(nameof(identities));
}

foreach (ClaimsIdentity identity in identities)
{
    if (identity != null)
    {
        return identity;
    }
}

return null;

也就是獲取Principal中第一個不為Null的Identity物件,這個取值邏輯可以通過下面的屬性進行修改:

public static Func<IEnumerable<ClaimsIdentity>, ClaimsIdentity?> PrimaryIdentitySelector { get; set; }

2.2 IsInRole

在Principal中,通常會存放一至多個Identity物件,每個 Identity物件有一至多個Claim物件,當有Claim物件的Type 值與Identity物件的:

public string RoleClaimType { get; }

值一致時,就會被認為該Claim里面存放著角色資訊,這時候會通過傳入的role值與Claim的Value進行比較,

比較的方法是Identity的實體方法HasClaim:

public virtual bool HasClaim(string type, string value);

如果初始化Identity時,沒有手動設定roleType引數,那么這個引數取值就是:

public const string DefaultRoleClaimType = ClaimTypes.Role;

通常情況下,不會單獨設定roleType,

2.3 IsAuthenticated 判斷是否登錄

這個屬性并不是ClaimPrincipal的,而是ClaimIdentity的,通常在asp.net core 中會使用這個屬性判斷訪問者是否完成了身份校驗,這個屬性的判斷邏輯也很簡單:

public virtual bool IsAuthenticated
{
    get { return !string.IsNullOrEmpty(AuthenticationType); }
}

也就是說,在Identity中指定了AuthenticationType就會認為完成了身份校驗,

通常的使用方式:

User.Identity.IsAuthenticated

通過以上呼叫鏈進行資料呼叫,

2.4 Name

與IsAuthenticatedy一樣,這個屬性也是ClaimIdentity的,與IsInRole的判斷依據類似,這個屬性會獲取Identity中存放的Claim集合中第一個RoleType為ClaimType.Name的Claim,然后取值,

所以,在實作登錄的時候,如果想要能夠通過:

User.Identity.Name

獲取一個用戶名資訊或者其他名稱資訊的話,則需要設定一個Type等于:

public const string DefaultNameClaimType = ClaimTypes.Name;

的Claim實體物件,

2.5 獲取Claim

在Principal體系中,最重要也是最基礎的資料就是Claim物件,對于ClaimPrincipal物件來說,里面必然會存放多個Claim物件,那么,我們就需要有操作Claim物件的方法:

public virtual IEnumerable<Claim> Claims { get; }

通過這個方法可以獲得ClaimPrincipal里所有的Claim物件,這是一個迭代器物件,

public virtual IEnumerable<Claim> FindAll(Predicate<Claim> match);

通過一個選擇器篩選出符合條件的Claim集合,

public virtual IEnumerable<Claim> FindAll(string type);

查詢所有符合型別的Claim物件,

public virtual Claim FindFirst(string type);

查找第一個Type值與指定值相同的Claim物件,

public virtual bool HasClaim(Predicate<Claim> match);

查詢是否存在符合條件的Claim物件,

public virtual bool HasClaim(string type, string value);

查詢是否有Type和Value屬性均等于指定值的Claim物件,

這些方法都是ClaimPrincipal里的,相對應的ClaimIdentity里也提供了類似的方法這里就不做介紹了,

3. 總結

這一章介紹了如何利用Claim進行用戶資訊保存,以及常規的一些使用邏輯,下一章,我們將繼續探索如何利用我們自己設定的Identity以達到我們的目的,

更多內容煩請關注我的博客《高先生小屋》

file

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/6420.html

標籤:C#

上一篇:MSIL入門(二)通過物件看IL

下一篇:WindowsForm如何移動一個沒有標題欄的視窗

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more