ASP.NET Core IdentityDbContext 身分驗證相關資料表介紹

在建立 ASP.NET Core 專案時,驗證類型選擇「個別帳戶」,就會自動加入 Microsoft.AspNetCore.Identity.EntityFrameworkCore 套件,會自動產生用於操作資料庫對應實體的 ApplicationDbContext,並繼承主要用於管理身分驗證相關資料的 IdentityDbContext。而 IdentityDbContext 預設總共會自動產生 7 張資料表,所有資料表如下:AspNetRoles, AspNetRoleClaims, AspNetUsers, AspNetUserClaims, AspNetUserLogins, AspNetUserRoles, AspNetUserTokens

以前剛開始接觸到時根本不知道這些是拿來做什麼的,也不知道可以修改資料表名稱,本篇就來介紹這些資料表分別的用途。
補充: 所有資料表都可以自行增加欄位,但是需要調整程式。本篇只著重說明原始資料表用途。

AspNetUsers 使用者資料表

這裡就是用來儲存「登入帳號」的地方,其中 UserName 和 Email 預設是不能重複的,而 NormalizedUserName 和 NormalizedEmail 就是前兩個轉大寫的內容。有些內建方法會使用 Email 尋找使用者,目前使用下來如果都不用的話可以設定為空白(介面上需額外調整)。
    
create table AspNetUsers
(
    Id                   nvarchar(450) not null
        constraint PK_AspNetUsers
            primary key,
    UserName             nvarchar(256),
    NormalizedUserName   nvarchar(256),
    Email                nvarchar(256),
    NormalizedEmail      nvarchar(256),
    EmailConfirmed       bit           not null,
    PasswordHash         nvarchar(max),
    SecurityStamp        nvarchar(max),
    ConcurrencyStamp     nvarchar(max),
    PhoneNumber          nvarchar(max),
    PhoneNumberConfirmed bit           not null,
    TwoFactorEnabled     bit           not null,
    LockoutEnd           datetimeoffset,
    LockoutEnabled       bit           not null,
    AccessFailedCount    int           not null
)
    

如果沒有需要使用,PhoneNumber 和 PhoneNumberConfirmed 欄位可以省略。

範例資料(只列出前幾個欄位):
    

+------------------------------------+--------+------------------+------------------------------------------------------------------------------------+-------+---------------+--------------+-----------+--------------------+-----------------+--------------------------------+------------------------------------+----------------+--------------+----------+
|Id                                  |UserName|NormalizedUserName|PasswordHash                                                                        |Email  |NormalizedEmail|EmailConfirmed|PhoneNumber|PhoneNumberConfirmed|AccessFailedCount|SecurityStamp                   |ConcurrencyStamp                    |TwoFactorEnabled|LockoutEnabled|LockoutEnd|
+------------------------------------+--------+------------------+------------------------------------------------------------------------------------+-------+---------------+--------------+-----------+--------------------+-----------------+--------------------------------+------------------------------------+----------------+--------------+----------+
|929e4114-342f-41c6-a33e-429b5ce26953|admin   |ADMIN             |AQAAAAEAACcQAAAAEC2f8tVgGfuL0baG3v8IRwiIjcWcqB750W+jmKhBKcMpZllpZfGGsIrflt5VGJu6qA==|a@ruyut|A@RUYUT        |false         |null       |false               |0                |7PNALWZC3EGMD5VZCGTN47OK7RFBIBEJ|a244a304-ab03-4552-83a8-255f7450a28a|false           |true          |null      |
+------------------------------------+--------+------------------+------------------------------------------------------------------------------------+-------+---------------+--------------+-----------+--------------------+-----------------+--------------------------------+------------------------------------+----------------+--------------+----------+

    

AspNetRoles 角色

角色類似於「群組」,一個角色可以關聯多個使用者,主要用作權限控制。例如系統管理員角色、一般使用者角色
    
create table AspNetRoles
(
    Id               nvarchar(450) not null
        constraint PK_AspNetRoles
            primary key,
    Name             nvarchar(256),
    NormalizedName   nvarchar(256),
    ConcurrencyStamp nvarchar(max)
)
    

    
+------------------------------------+-----+--------------+------------------------------------+
|Id                                  |Name |NormalizedName|ConcurrencyStamp                    |
+------------------------------------+-----+--------------+------------------------------------+
|3b23daa8-e7c2-4e4f-be5e-9fc568f99d97|Admin|ADMIN         |ce4d4647-b65d-4214-b5e3-cb70c10cff02|
+------------------------------------+-----+--------------+------------------------------------+
    

AspNetUserRoles 使用者和角色的多對多關聯

用來紀錄哪個使用者是哪個角色
    
create table AspNetUserRoles
(
    UserId nvarchar(450) not null
        constraint FK_AspNetUserRoles_AspNetUsers_UserId
            references AspNetUsers
            on delete cascade,
    RoleId nvarchar(450) not null
        constraint FK_AspNetUserRoles_AspNetRoles_RoleId
            references AspNetRoles
            on delete cascade,
    constraint PK_AspNetUserRoles
        primary key (UserId, RoleId)
)
    

範例資料
    
+------------------------------------+------------------------------------+
|UserId                              |RoleId                              |
+------------------------------------+------------------------------------+
|929e4114-342f-41c6-a33e-429b5ce26953|3b23daa8-e7c2-4e4f-be5e-9fc568f99d97|
+------------------------------------+------------------------------------+
    

AspNetRoleClaims 角色宣告(聲明、索賠)

AspNetRoleClaims 主要是用來儲存「角色」的自定義資訊,也可以被用來儲存這個角色有哪些「權限」
    
create table AspNetRoleClaims
(
    Id         int identity
        constraint PK_AspNetRoleClaims
            primary key,
    RoleId     nvarchar(450) not null
        constraint FK_AspNetRoleClaims_AspNetRoles_RoleId
            references AspNetRoles
            on delete cascade,
    ClaimType  nvarchar(max),
    ClaimValue nvarchar(max)
)
    

這是一種「角色宣告」的資料儲存方式:
    
+---+------------------------------------+----------+-------------------------+
|Id |RoleId                              |ClaimType |ClaimValue               |
+---+------------------------------------+----------+-------------------------+
|1  |3b23daa8-e7c2-4e4f-be5e-9fc568f99d97|Permission|UserManager.Read         |
|2  |3b23daa8-e7c2-4e4f-be5e-9fc568f99d97|Permission|UserManager.Create       |
|3  |3b23daa8-e7c2-4e4f-be5e-9fc568f99d97|Permission|UserManager.Update       |
|4  |3b23daa8-e7c2-4e4f-be5e-9fc568f99d97|Permission|UserManager.Delete       |
+---+------------------------------------+----------+-------------------------+
    

當然 ClaimType 中還可以儲存其他自訂內容

AspNetUserClaims 使用者宣告(聲明、索賠)

和上方 AspNetRoleClaims 類似,AspNetUserClaims 也是是用來儲存「使用者」的自定義資訊,也可以被用來儲存這個角色有哪些「權限」
    
create table AspNetUserClaims
(
    Id         int identity
        constraint PK_AspNetUserClaims
            primary key,
    UserId     nvarchar(450) not null
        constraint FK_AspNetUserClaims_AspNetUsers_UserId
            references AspNetUsers
            on delete cascade,
    ClaimType  nvarchar(max),
    ClaimValue nvarchar(max)
)
    

可以查看 ClaimTypes 「列舉」(其實他是靜態類別,不是 enum,裡面使用常數字串列出常見的「宣告」) 來參考常見的類型名稱,當然都可以填入自訂內容。
    
    public static class ClaimTypes
    {
        public const string HomePhone = ClaimType2005Namespace + "/homephone";
        public const string MobilePhone = ClaimType2005Namespace + "/mobilephone";
        public const string StateOrProvince = ClaimType2005Namespace + "/stateorprovince";
        public const string StreetAddress = ClaimType2005Namespace + "/streetaddress";
        public const string Thumbprint = ClaimType2005Namespace + "/thumbprint";
        
        // ...
    }
    

AspNetUserLogins 使用者登入資訊

AspNetUserLogins 是用來儲存第三方登入(例如 Google, Apple, Facebook, Line 登入)的資訊,每一筆是一個使用者和一個第三方登入的資訊。
    
create table AspNetUserLogins
(
    LoginProvider       nvarchar(128) not null,
    ProviderKey         nvarchar(128) not null,
    ProviderDisplayName nvarchar(max),
    UserId              nvarchar(450) not null
        constraint FK_AspNetUserLogins_AspNetUsers_UserId
            references AspNetUsers
            on delete cascade,
    constraint PK_AspNetUserLogins
        primary key (LoginProvider, ProviderKey)
)
    

AspNetUserTokens 使用者令牌

用來儲存外部身份驗證令牌
    
create table AspNetUserTokens
(
    UserId        nvarchar(450) not null
        constraint FK_AspNetUserTokens_AspNetUsers_UserId
            references AspNetUsers
            on delete cascade,
    LoginProvider nvarchar(128) not null,
    Name          nvarchar(128) not null,
    Value         nvarchar(max),
    constraint PK_AspNetUserTokens
        primary key (UserId, LoginProvider, Name)
)
    



參考資料:
Microsoft.Learn - Microsoft.AspNetCore.Identity.EntityFrameworkCore Namespace
Microsoft.Learn - ClaimTypes Class
StackOverflow - Asp.net Core Identity Use AspNetUserClaims or AspNetRoleClaims?
StackOverflow - The AspNetUserLogins table Identity

留言