ASP.NET MVC Custom RoleProvider

2023-01-28

筆記如何客製 ASP.NET RoleProvider,從而實現使用 AuthorizeAttribute 驗證使用者的 Roles 時,定義 Roles 的來源。

logo

說明

Custom Provider

需要在專案中加入類別,並繼承 RoleProvider 後覆寫相關方法。

Custom/CustomRoleProvider.cs

public class CustomRoleProvider : RoleProvider
{
    public override string ApplicationName
    {
      get => throw new NotImplementedException();
      set => throw new NotImplementedException();
    }

    public override string[] GetRolesForUser(string username)
    {
        return new string[] { "Admin" };
    }

    public override bool IsUserInRole(string username, string roleName)
    {
        throw new NotImplementedException();
    }

    public override string[] GetUsersInRole(string roleName)
    {
        throw new NotImplementedException();
    }

    public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }

    public override bool RoleExists(string roleName)
    {
        throw new NotImplementedException();
    }

    public override void AddUsersToRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }

    public override void CreateRole(string roleName)
    {
        throw new NotImplementedException();
    }

    public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
    {
        throw new NotImplementedException();
    }

    public override string[] FindUsersInRole(string roleName, string usernameToMatch)
    {
        throw new NotImplementedException();
    }

    public override string[] GetAllRoles()
    {
        throw new NotImplementedException();
    }
}

接著在 Config 加入 RoleProvider 的註冊。

Web.config

<system.web>
  <roleManager enabled="true" defaultProvider="CustomRoleProvider">
  <providers>
  <clear />
  <add name="CustomRoleProvider" type="NorthwindShop2.Web.Custom.CustomRoleProvider" />
  </providers>
  </roleManager>
</system.web>

ASP.NET Identity Database Schema

在客製化 Role 的資料儲存上,仍可以參考 ASP.NET Identity 的設置方式,並且在依照需求進行客製。

dbo.AspNetUsers

CREATE TABLE [dbo].[AspNetUsers](
	[Id] [nvarchar](128) NOT NULL,
	[Email] [nvarchar](256) NULL,
	[EmailConfirmed] [bit] NOT NULL,
	[PasswordHash] [nvarchar](max) NULL,
	[SecurityStamp] [nvarchar](max) NULL,
	[PhoneNumber] [nvarchar](max) NULL,
	[PhoneNumberConfirmed] [bit] NOT NULL,
	[TwoFactorEnabled] [bit] NOT NULL,
	[LockoutEndDateUtc] [datetime] NULL,
	[LockoutEnabled] [bit] NOT NULL,
	[AccessFailedCount] [int] NOT NULL,
	[UserName] [nvarchar](256) NOT NULL,
 CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
) WITH (
  PAD_INDEX = OFF, 
  STATISTICS_NORECOMPUTE = OFF, 
  IGNORE_DUP_KEY = OFF, 
  ALLOW_ROW_LOCKS = ON, 
  ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

dbo.AspNetRoles

CREATE TABLE [dbo].[AspNetRoles](
	[Id] [nvarchar](128) NOT NULL,
	[Name] [nvarchar](256) NOT NULL,
 CONSTRAINT [PK_dbo.AspNetRoles] PRIMARY KEY CLUSTERED
(
	[Id] ASC
) WITH (
  PAD_INDEX = OFF, 
  STATISTICS_NORECOMPUTE = OFF, 
  IGNORE_DUP_KEY = OFF, 
  ALLOW_ROW_LOCKS = ON, 
  ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

dbo.AspNetUserRoles

CREATE TABLE [dbo].[AspNetUserRoles](
	[UserId] [nvarchar](128) NOT NULL,
	[RoleId] [nvarchar](128) NOT NULL,
 CONSTRAINT [PK_dbo.AspNetUserRoles] PRIMARY KEY CLUSTERED
(
	[UserId] ASC,
	[RoleId] ASC
) WITH (
  PAD_INDEX = OFF, 
  STATISTICS_NORECOMPUTE = OFF, 
  IGNORE_DUP_KEY = OFF, 
  ALLOW_ROW_LOCKS = ON, 
  ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[AspNetUserRoles] 
  WITH CHECK ADD CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId] 
  FOREIGN KEY([RoleId])
  REFERENCES [dbo].[AspNetRoles] ([Id])
  ON DELETE CASCADE
GO

ALTER TABLE [dbo].[AspNetUserRoles] CHECK CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId]
GO

ALTER TABLE [dbo].[AspNetUserRoles]  WITH CHECK ADD 
  CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId] 
  FOREIGN KEY([UserId])
  REFERENCES [dbo].[AspNetUsers] ([Id])
  ON DELETE CASCADE
GO

ALTER TABLE [dbo].[AspNetUserRoles] CHECK CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId]
GO

需要注意在匿名驗證的情況下,Authorize Filter 不會發揮作用,必須要是 Windows 驗證或者是 Form 驗證才能夠搭配 Authorize Filter 使用。

相關連結

ASP.NET MVC 5 如何客製化驗證與授權並實作帳號登入機制 (How to custom ASP.NET MVC Auth Filters & Login / Logoff systems)

參考資料

ASP.NET MVC How to create a custom role provider | stackoverflow