.NET Core Security: Authentication

Authentication là quá trình xác thực danh tính của một user khi truy cập API, giải quyết câu hỏi: “Đây có thật sự là user Nguyễn Văn A như anh ta tự xưng hay không?”. Khác với authorization, là quá trình phân quyền, xảy ra xau khi xác thực thành công, trả lời cho câu hỏi: “Anh A có quyền truy cập tài nguyên này hay không?”
Trong .NET Core, sau khi xác thực thành công, .NET Core sẽ khởi tạo một identity object gọi là ClaimsPrincipal
đại diện cho user và chứa thông tin của user. Chúng ta có thể truy cập nó thông qua HttpContext.User
. Và bên trong Principal object này là 1 list các Claim
tức là các thuộc tính của user này.
Một flow authentication thông thường sẽ bao gồm các bước sau:
Client gửi username và password xuống cho server, đại diện cho một lần xưng tên tuổi
Server xác nhận username password khớp với user tồn tại trong database.
Sau khi xác nhận, server khởi tạo Principal riêng cho request hiện tại
Authentication thông thường sẽ được .NET Core xử lý thông qua Authentication Middleware như sau
class Program {
public static void Main() {
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication();
builder.Services.AddControllers();
var app = builder.Build();
app.UseAuthentication();
app.MapControllers();
app.Run();
}
}
Các phương pháp authentication
Nhưng có một vấn đề ở đây, vậy những lần giao tiếp tiếp theo với cùng User đó thì cứ xác thực lặp lại à?. Đúng đó cũng là một cách (Basic Authentication), thông thường có vài cách và ta có thể config được dùng cách nào ở hàm AddAuthentication()
ở WebApplicationBuilder
:
No Authentication, sử dụng
[AllowAnonymous]
attributeBasic Authentication, client gửi username password trong Authorization header của mọi request và được encode base64
Authorization: Basic <base64-encoded-username-password>
. Cách này dễ hiểu dễ implement ở client-side, tuy nhiên là xác thực lặp lại, bảo mật yếu và .NET Core cũng không build sẵn cơ chế, phải viết customAuthenticationHandler
hoặc tìm 3rd party libraryCookie Authentication: Sau khi xác thực thành công, server trả về cho client
Set-Cookie
header chứa thông tin của User để tránh việc xác thực lặp lạibuilder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Account/Login"; options.AccessDeniedPath = "/Account/AccessDenied"; // ... });
Auth header Authentication: Bearer JWT (Jason Web token) đang là phương pháp phổ biến nhất ở web api hiện đại, khi client là web Single Page app hoặc mobile app.
Server xác thực thông tin xác thực và cấp JWT. JWT là chuỗi chứa dữ liệu JSON được mã hóa (header, payload, signature). Payload thường bao gồm thông tin User và thời gian hết hạn.
Client lưu trữ JWT (ví dụ: trong local storage, session storage). Client gửi JWT trong Authorization header trên các request tiếp theo (
Authorization: Bearer <jwt_token>
).Server xác thực lại JWT. Nếu hợp lệ, server sẽ trích xuất thông tin User từ payload để tạo
ClaimsPrincipal
.
// JWT settings (thông thường lấy từ appsettings.json)
var jwtSettings = builder.Configuration.GetSection("JwtSettings");
var secretKey = Encoding.ASCII.GetBytes(jwtSettings["SecretKey"]); // STORE SECURELY!
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = true; // Always true in production
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
// ...
};
});
Uỷ thác cho service khác (OAuth 2.0 / OpenID Connect):
Ủy quyền xác thực cho các authentication service bên ngoài như Google, Facebook, Azure Active Directory (Azure AD), IdentityServer, Auth0, v.v. Sử dụng các giao thức như OAuth 2.0 và OpenID Connect. Người dùng có thể đăng nhập bằng tài khoản ở nơi khác có sẵn. Tận dụng cơ sở hạ tầng bảo mật mạnh mẽ có sẵn của các hệ thống chuyên biệt, đơn giản hóa việc quản lý người dùng cho server. Đây cũng là phương pháp xác thực bắt buộc phải có trong hệ thống microservices. Tuy nhiên điều này cũng có nhược điểm là tạo ra sự phụ thuộc vào nhà cung cấp bên ngoài hoặc phải học cấu hình phức tạp. Chúng ta sẽ không bàn tới phương pháp này ở đây vì sự phức tạp của nó xứng đáng có một series riêng.
.NET Core Identity
Nền tảng
.NET Core Identity (sau đây gọi tắt là Identity) là một library đơn giản hỗ trợ developer nhanh chóng tự xây được module quản lý người dùng của backend server, hỗ trợ cả 2 phương pháp Cookie và Auth header. Và nó xử lý tất cả các boilerplate để lưu và tải người dùng vào database, cũng như một số best practices về bảo mật, chẳng hạn như khóa người dùng, băm mật khẩu và xác thực hai yếu tố.
Mặc dù hoàn toàn có thể tự viết toàn bộ mã để xây module quản lý người dùng theo ý muốn của riêng mình, nhưng ngoài mục đích để học tập ra thì không nên làm vậy.
Mặc định Identity sử dụng EF Core để lưu trữ thông tin chi tiết về người dùng trong database. Vì vậy nếu ta đã dùng sẵn EF Core trong dự án của mình, thì đây là lựa chọn hoàn hảo (thật ra ai mà chẳng dùng EF Core). Nhưng nếu thích thì ta hoàn toàn có thể viết cơ chế lưu trữ cho Identity theo cách khác.
Identity xử lý các phần cấp thấp của quản lý người dùng, như được hiển thị trong bảng dưới đây.
Quản lý bởi Identity | Developer tự cài đặt |
Database schema để lưu trữ User , Role và Claim | Custom UI để login, quản lý user |
Tạo, sửa user | Gửi email và SMS |
Validate password, email và rules | Thêm custom Claim |
Xử lý lockout chống brute force | Cấu hình xác thực bên thứ 3 |
Quản lý 2FA code | |
Sinh password reset token | |
Lưu custom Claim vào database | |
Quản lý xác thực với bên thứ 3 (Facebook, Google, Twitter) | |
Default MVC UI Components |
Như ta có thể thấy từ danh sách này, Identity cung cấp cho chúng ta rất nhiều, nhưng không phải tất cả. Phần còn thiếu lớn nhất là thực tế là ta cần tự xây UI, cũng như liên kết tất cả các service Identity riêng lẻ lại với nhau để tạo ra một quy trình đăng nhập hoạt động. Đó là một phần còn thiếu khá lớn, nhưng đó là quyết định của .NET Core team, giúp cho hệ thống Identity cực kỳ linh hoạt.
Cải tiến trong .NET 8
Identity API Endpoints: Đây có thể được coi là tính năng liên quan đến Identity lớn nhất trong .NET 8.
.NET 8 cung cấp built-in minimal API endpoints để quản lý authentication (register, login, refresh token, confirm email, forgot password, reset password, manage user info, manage 2FA, etc.).
Đăng ký với DI Container bằng lệnh builder.Services.AddIdentityApiEndpoints()
và map endpoints bằng app.MapIdentityApi()
. Các endpoint này xử lý các request và response JSON và thường hoạt động với phường pháp xác thực Bearer Token (JWT), phù hợp với API và SPA.
Subscribe to my newsletter
Read articles from Anh Phan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
