Ủy quyền dựa trên Role trong ASP.NET Core MVC
Khi danh tính của người dùng được tạo sau khi xác thực, người dùng có thể thuộc một hoặc nhiều role (vai trò), phản ánh các ủy quyền khác nhau mà người dùng có để truy cập dữ liệu và thực hiện các thao tác. Ví dụ, Tracy có thể thuộc role "Administrator" và "User" với quyền truy cập các trang web quản trị trong ứng dụng, trong khi Scott chỉ có thể thuộc role "User" và không có quyền truy cập dữ liệu hay thao tác quản trị. Cách tạo và quản lý các role này phụ thuộc vào backing store (kho lưu trữ) của quy trình authorization. Các role được hiển thị cho nhà phát triển thông qua ClaimsPrincipal.IsInRole. Cần gọi AddRoles để thêm Role services khi thiết lập hệ thống identity của ứng dụng.
Mặc dù role là claim (yêu cầu), nhưng không phải tất cả claim đều là role. Tùy thuộc vào identity issuer (nhà phát hành danh tính), một role có thể là tập hợp người dùng có thể áp dụng claim cho các thành viên nhóm, cũng như một actual claim trên một danh tính. Tuy nhiên, claim được thiết kế để cung cấp thông tin về một người dùng cụ thể. Sử dụng role để thêm claim cho người dùng có thể làm nhòa ranh giới giữa người dùng và claim cá nhân của họ. Đây là lý do tại sao các template single-page application (SPA) không được thiết kế xung quanh role. Ngoài ra, đối với các tổ chức di chuyển từ hệ thống legacy on-premises, sự phổ biến của role trong nhiều năm có thể có nghĩa là một role claim có thể quá lớn để chứa trong một token có thể sử dụng bởi SPA. Để bảo mật SPA, xem Use Identity to secure a Web API backend for SPAs.
Bài viết này sử dụng các ví dụ MVC và tập trung vào các kịch bản MVC. Để biết hướng dẫn về Blazor và Razor Pages, xem các tài nguyên sau:
Thêm Role services vào Identity
Đăng ký các dịch vụ authorization dựa trên role trong file Program bằng cách gọi AddRoles với kiểu role trong cấu hình Identity của ứng dụng. Kiểu role trong ví dụ sau là IdentityRole:
builder.Services.AddDefaultIdentity<IdentityUser>( ... )
.AddRoles<IdentityRole>()
...Code trên yêu cầu NuGet package Microsoft.AspNetCore.Identity.UI và chỉ thị using cho Microsoft.AspNetCore.Identity.
Trong các trường hợp ứng dụng kiểm soát chi tiết để xây dựng Identity thủ công, hãy gọi AddRoles trên AddIdentityCore:
builder.Services.AddIdentityCore<IdentityUser>()
.AddRoles<IdentityRole>()
...Kiểm tra authorization dựa trên Role
Các kiểm tra authorization dựa trên role:
- Mang tính khai báo và chỉ định các role mà người dùng hiện tại phải là thành viên để truy cập tài nguyên được yêu cầu.
- Được áp dụng cho controllers hoặc actions trong một controller.
Ví dụ, code sau giới hạn truy cập vào bất kỳ action nào trên một controller cho người dùng là thành viên của role Administrator:
[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
...
}Có thể chỉ định nhiều role dưới dạng danh sách phân cách bằng dấu phẩy. Trong ví dụ sau, truy cập bị giới hạn cho người dùng là thành viên của role HRManager hoặc role Finance:
[Authorize(Roles = "HRManager, Finance")]
public class SalaryController : Controller
{
...
}Khi nhiều thuộc tính được áp dụng, người dùng phải là thành viên của tất cả các role được chỉ định. Ví dụ sau yêu cầu cả hai role PowerUser và ControlPanelUser để gọi các action SetTime và Shutdown:
[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
public class ControlPanelController : Controller
{
public IActionResult SetTime() { ... }
public IActionResult ShutDown() { ... }
}Truy cập vào một action có thể bị giới hạn bằng cách áp dụng thêm các thuộc tính role authorization ở cấp độ action:
[Authorize(Roles = "Administrator, PowerUser")]
public class ControlPanelController : Controller
{
public IActionResult SetTime() { ... }
[Authorize(Roles = "Administrator")]
public IActionResult ShutDown() { ... }
}Trong controller trên:
- Thành viên của role
Administratorhoặc rolePowerUsercó thể truy cập controller và actionSetTime. - Chỉ thành viên của role
Administratormới có thể truy cập actionShutDown.
Một controller có thể được bảo mật nhưng vẫn cho phép truy cập ẩn danh, không xác thực vào các action riêng lẻ với thuộc tính [AllowAnonymous]:
[Authorize]
public class Control3PanelController : Controller
{
public IActionResult SetTime() { ... }
[AllowAnonymous]
public IActionResult Login() { ... }
}Khớp role thường phân biệt chữ hoa chữ thường vì tên role được lưu trữ và so sánh bằng cách sử dụng so sánh chuỗi .NET. Ví dụ, Admin (chữ A viết hoa) không được coi là cùng role với admin (chữ a viết thường). Để biết thêm thông tin, xem Claim-based authorization in ASP.NET Core.
Kiểm tra authorization dựa trên Policy
Các yêu cầu về role có thể được diễn đạt bằng cú pháp policy, trong đó ứng dụng đăng ký một policy khi khởi động như một phần của cấu hình Authorization service. Trong ví dụ sau, policy RequireAdministratorRole chỉ định rằng tất cả người dùng phải thuộc role Administrator:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("RequireAdministratorRole",
policy => policy.RequireRole("Administrator"));Các policy được áp dụng bằng cách sử dụng thuộc tính Policy trên thuộc tính [Authorize]:
[Authorize(Policy = "RequireAdministratorRole")]
public IActionResult Shutdown() { ... }Ngược lại với khớp role thường phân biệt chữ hoa chữ thường, việc tra cứu tên policy trong ASP.NET Core thường không phân biệt chữ hoa chữ thường, vì vậy RequireAdministratorRole và requireadministratorrole đề cập đến cùng một policy.
Để chỉ định nhiều role được phép trong một yêu cầu, hãy chỉ định các role làm tham số cho phương thức RequireRole. Trong ví dụ sau, người dùng được ủy quyền nếu họ thuộc role Administrator, PowerUser, hoặc BackupAdministrator:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("ElevatedRights", policy =>
policy.RequireRole("Administrator", "PowerUser", "BackupAdministrator"));Nếu bạn muốn policy yêu cầu tất cả các role trên, hãy chuỗi các role vào policy builder hoặc chỉ định chúng cho policy builder riêng lẻ trong một statement lambda.
Chuỗi vào policy builder:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("ElevatedRights", policy =>
policy
.RequireRole("Administrator")
.RequireRole("PowerUser")
.RequireRole("BackupAdministrator"));Hoặc, sử dụng statement lambda:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("ElevatedRights",
policy =>
{
policy.RequireRole("Administrator");
policy.RequireRole("PowerUser");
policy.RequireRole("BackupAdministrator");
});Nhóm bảo mật Windows Authentication là app roles
Sau khi ứng dụng được cấu hình cho Windows Authentication với máy khách và máy chủ là một phần của cùng Windows domain, các security group (nhóm bảo mật) của người dùng tự động được bao gồm như là claim trong ClaimsPrincipal của người dùng.
User.Identity thường là WindowsIdentity khi sử dụng Windows Authentication, và bạn có thể lấy SID group claims hoặc kiểm tra xem người dùng có thuộc role bằng code sau, trong đó placeholder {DOMAIN} là domain và {SID GROUP NAME} là tên SID group:
if (User.Identity is WindowsIdentity windowsIdentity)
{
var groups = windowsIdentity.Groups;
// Nếu cần, lấy danh sách các SID group
var securityGroups =
groups.Select(g => g.Translate(typeof(NTAccount)).ToString()).ToList();
// Nếu cần, lấy tên Windows identity của người dùng
var windowsIdentityName = windowsIdentity.Name;
// Kiểm tra xem người dùng có thuộc SID group cụ thể không
if (User.IsInRole(@"{DOMAIN}\{SID GROUP NAME}"))
{
// Người dùng thuộc nhóm được chỉ định
}
else
{
// Người dùng không thuộc nhóm được chỉ định
}
}
else
{
// Người dùng không xác thực với Windows Authentication
}Cách tiếp cận tương tự ví dụ trên để lấy SID group claims có thể kết hợp với thêm claims bằng IClaimsTransformation để tạo custom role claims khi người dùng được xác thực.