Xác thực và phân quyền trong Minimal APIs
Minimal APIs hỗ trợ tất cả các tùy chọn authentication (xác thực) và authorization (phân quyền) có sẵn trong ASP.NET Core, đồng thời cung cấp thêm chức năng để cải thiện trải nghiệm quản lý xác thực.
Bài viết này mô tả hỗ trợ cho authentication và authorization trong ứng dụng Minimal API, cũng như cách cấu hình và kiểm thử chức năng này.
Tổng quan các khái niệm Authentication và Authorization
Authentication là quá trình xác định danh tính của người dùng trong khi authorization là quá trình xác định xem người dùng có quyền truy cập vào tài nguyên hay không. Cả hai kịch bản authentication và authorization đều có semantic (ngữ nghĩa) triển khai tương tự trong ASP.NET Core.
- Authentication service (dịch vụ xác thực), IAuthenticationService, xử lý tất cả authentication và được sử dụng bởi authentication middleware.
- Authorization service (dịch vụ phân quyền), IAuthorizationService, quản lý tất cả authorization và được sử dụng bởi authorization middleware.
Authentication service
Authentication service sử dụng các authentication handler (trình xử lý xác thực) đã đăng ký để hoàn thành các hành động liên quan đến authentication. Ví dụ, một hành động liên quan đến authentication là xác thực người dùng hoặc đăng xuất người dùng. Authentication scheme (lược đồ xác thực) là tên được dùng để định danh duy nhất một authentication handler và các tùy chọn cấu hình của nó. Authentication handler chịu trách nhiệm triển khai các chiến lược authentication và tạo ra các claim (yêu cầu) của người dùng dựa trên một chiến lược authentication cụ thể, chẳng hạn như OAuth hoặc OIDC. Các tùy chọn cấu hình là duy nhất cho từng chiến lược và cung cấp cho handler cấu hình ảnh hưởng đến hành vi authentication, chẳng hạn như redirect URI.
Authorization service
Trong lớp authorization, có hai chiến lược để xác định quyền truy cập tài nguyên của người dùng:
- Chiến lược dựa trên Role (vai trò) xác định quyền truy cập của người dùng dựa trên vai trò được gán cho họ, chẳng hạn như
AdministratorhoặcUser. Để biết thêm về role-based authorization, xem tài liệu role-based authorization. - Chiến lược dựa trên Claim (yêu cầu) xác định quyền truy cập của người dùng dựa trên các claim do cơ quan trung tâm cấp. Để biết thêm về claim-based authorization, xem tài liệu claim-based authorization.
Trong ASP.NET Core, cả hai chiến lược đều được ghi lại thành authorization requirement (yêu cầu phân quyền). Authorization service sử dụng authorization handler (trình xử lý phân quyền) để xác định xem một người dùng cụ thể có đáp ứng các authorization requirement cho một tài nguyên hay không.
Bật authentication trong minimal apps
Để bật authentication, gọi phương thức AddAuthentication để đăng ký các authentication service cần thiết vào service provider của ứng dụng.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication();
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();Thông thường, một chiến lược authentication cụ thể được sử dụng. Trong ví dụ sau, ứng dụng được cấu hình với hỗ trợ JSON Web Token (JWT) bearer-based authentication (xác thực dựa trên bearer token JWT). Ví dụ này sử dụng các API có trong gói NuGet Microsoft.AspNetCore.Authentication.JwtBearer.
var builder = WebApplication.CreateBuilder(args);
// Yêu cầu Microsoft.AspNetCore.Authentication.JwtBearer
builder.Services.AddAuthentication().AddJwtBearer();
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();Theo mặc định, WebApplication tự động đăng ký authentication và authorization middleware nếu một số authentication và authorization service được bật. Trong ví dụ sau, không cần thiết phải gọi UseAuthentication hoặc UseAuthorization để đăng ký middleware. WebApplication tự động hoàn thành việc đăng ký sau khi gọi phương thức AddAuthentication hoặc AddAuthorization.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();Trong một số trường hợp, chẳng hạn như kiểm soát thứ tự middleware, cần thiết phải đăng ký authentication và authorization một cách tường minh. Trong ví dụ sau, authentication middleware chạy sau khi CORS middleware chạy. Để biết thêm về middleware và hành vi tự động này, xem Middleware trong ứng dụng Minimal API.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", () => "Hello World!");
app.Run();Cấu hình chiến lược authentication
Các chiến lược authentication thường hỗ trợ nhiều cấu hình khác nhau được tải qua options. Minimal apps hỗ trợ tải options từ configuration cho các chiến lược authentication sau:
ASP.NET Core framework kỳ vọng tìm thấy các options này trong phần Authentication:Schemes:{SchemeName} trong configuration. Trong ví dụ sau, hai scheme khác nhau, Bearer và LocalAuthIssuer, được xác định với các options tương ứng. Tùy chọn Authentication:DefaultScheme có thể được dùng để cấu hình chiến lược authentication mặc định.
{
"Authentication": {
"DefaultScheme": "LocalAuthIssuer",
"Schemes": {
"Bearer": {
"ValidAudiences": [
"https://localhost:7259",
"http://localhost:5259"
],
"ValidIssuer": "dotnet-user-jwts"
},
"LocalAuthIssuer": {
"ValidAudiences": [
"https://localhost:7259",
"http://localhost:5259"
],
"ValidIssuer": "local-auth"
}
}
}
}Trong file Program.cs, hai chiến lược JWT bearer-based authentication được đăng ký với các scheme name sau:
- "Bearer"
- "LocalAuthIssuer"
"Bearer" là scheme mặc định thông thường trong các ứng dụng được bật JWT-bearer. Tuy nhiên, bạn có thể ghi đè scheme mặc định bằng cách đặt thuộc tính DefaultScheme như trong ví dụ trước.
Scheme name được dùng để định danh duy nhất một chiến lược authentication. Tên này cũng được dùng là lookup key (khóa tra cứu) khi giải quyết authentication options từ config, như trong ví dụ sau:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication()
.AddJwtBearer()
.AddJwtBearer("LocalAuthIssuer");
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();Cấu hình authorization policy (chính sách phân quyền) trong minimal apps
Authentication xác định và xác nhận danh tính của người dùng đối với API. Authorization xác nhận và kiểm tra quyền truy cập vào tài nguyên trong API. Service IAuthorizationService được đăng ký bởi extension method AddAuthorization giúp thực hiện authorization. Trong kịch bản sau, tài nguyên /hello được thêm yêu cầu người dùng phải xuất trình claim admin role với claim scope greetings_api.
Việc cấu hình các authorization requirement trên tài nguyên là một quy trình hai bước:
- Xác định các authorization requirement trong một policy một cách toàn cục.
- Áp dụng các policy riêng lẻ lên tài nguyên.
Trong đoạn code sau, phương thức AddAuthorizationBuilder được gọi, thực hiện:
- Thêm các service liên quan đến authorization vào DI container.
- Trả về object AuthorizationBuilder có thể được dùng để đăng ký trực tiếp các authorization policy.
Code tạo một authorization policy mới có tên admin_greetings bao gồm hai authorization requirement:
- Yêu cầu dựa trên role thông qua RequireRole cho người dùng có role
admin. - Yêu cầu dựa trên claim thông qua RequireClaim mà người dùng phải cung cấp claim scope
greetings_api.
Policy admin_greetings được cung cấp là policy bắt buộc cho endpoint /hello:
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorizationBuilder()
.AddPolicy("admin_greetings", policy =>
policy
.RequireRole("admin")
.RequireClaim("scope", "greetings_api"));
var app = builder.Build();
app.MapGet("/hello", () => "Hello world!")
.RequireAuthorization("admin_greetings");
app.Run();Sử dụng 'dotnet user-jwts' để kiểm thử trong môi trường development
Các ví dụ trong bài viết này sử dụng ứng dụng được cấu hình với JWT bearer-based authentication. JWT bearer-based authentication yêu cầu client xuất trình token trong request header, được dùng để xác thực danh tính và claim của họ. Thông thường, một cơ quan trung tâm như identity server cấp phát các token này.
Để phát triển trên máy local, công cụ dòng lệnh dotnet user-jwts có thể được dùng để tạo bearer token.
dotnet user-jwts create
Lưu ý: Khi được gọi trên một project, công cụ tự động thêm các authentication option phù hợp với token được tạo vào file appsettings.json.
Token có thể được cấu hình với nhiều tùy chỉnh khác nhau. Ví dụ, để tạo token cho role admin và scope greetings_api mà authorization policy trong code trên mong đợi, hãy chạy công cụ như sau:
dotnet user-jwts create --scope "greetings_api" --role "admin"
Token được tạo ra sau đó có thể được gửi như một phần của header trong công cụ kiểm thử theo lựa chọn. Ví dụ, để gửi token với curl:
curl -i -H "Authorization: Bearer {token}" https://localhost:{port}/hello