Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bảo mật

Authentication (Xác thực)

JWT (JSON Web Token)

JWT là một chuẩn token để truyền thông tin an toàn giữa các parties dưới dạng JSON.

Cấu trúc JWT

┌─────────────────────────────────────────────────────────────────────┐
│                        JWT STRUCTURE                                │
├─────────────────┬─────────────────┬───────────────────────────────┤
│    HEADER       │     PAYLOAD     │         SIGNATURE             │
│  (Base64URL)    │   (Base64URL)   │       (Base64URL)             │
├─────────────────┼─────────────────┼───────────────────────────────┤
│ {               │ {               │ HmacSHA256(                   │
│   "alg":        │   "sub":        │   header + "." + payload,     │
│     "HS256",    │     "1234567890",│   secret_key                  │
│   "typ":        │   "name":       │ )                             │
│     "JWT"       │     "John Doe", │                               │
│ }               │   "iat":         │                               │
│                 │     1516239022,  │                               │
│                 │   "exp":         │                               │
│                 │     1516242622   │                               │
│                 │ }               │                               │
└─────────────────┴─────────────────┴───────────────────────────────┘

Cấu hình JwtBearer trong .NET Core

// Program.cs
var builder = WebApplication.CreateBuilder(args);

// Add Authentication
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = builder.Configuration["Jwt:Issuer"],
        ValidAudience = builder.Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"]))
    };
});

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

Tạo JWT Token

public class JwtService
{
    private readonly JwtSettings _settings;
    
    public string GenerateToken(User user)
    {
        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
            new Claim(JwtRegisteredClaimNames.Email, user.Email),
            new Claim(ClaimTypes.Role, user.Role),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };
        
        var key = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(_settings.SecretKey));
        var credentials = new SigningCredentials(
            key, SecurityAlgorithms.HmacSha256);
        
        var token = new JwtSecurityToken(
            issuer: _settings.Issuer,
            audience: _settings.Audience,
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(_settings.ExpiryMinutes),
            signingCredentials: credentials);
        
        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

Authorization (Phân quyền)

[Authorize] Attribute

// Yêu cầu authenticate
[Authorize]
[HttpGet("profile")]
public IActionResult GetProfile() { }

// Yêu cầu role cụ thể
[Authorize(Roles = "Admin")]
[HttpGet("admin")]
public IActionResult GetAdminData() { }

// Yêu cầu nhiều roles (AND logic)
[Authorize(Roles = "Admin,Manager")]
[HttpGet("manage")]
public IActionResult Manage() { }

// Yếu tố OR - dùng Policy
[Authorize(Policy = "AdminOrManager")]
[HttpGet("manage")]
public IActionResult Manage() { }

Role-based Authorization

[Authorize(Roles = "Admin")]
public class AdminController : ControllerBase
{
    [HttpGet("users")]
    public IActionResult GetAllUsers()
    {
        // Only admins can access
        return Ok();
    }
}

Policy-based Authorization

// Đăng ký policy trong Program.cs
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdultOnly", policy =>
        policy.RequireClaim("Age", "18", "19", "20", "21", "22", "23", "24", "25"));
    
    options.AddPolicy("PremiumUser", policy =>
        policy.RequireAssertion(context =>
            context.User.HasClaim(c => c.Type == "Subscription" && 
                                      c.Value == "Premium")));
    
    options.AddPolicy("CanDeleteProduct", policy =>
        policy.RequireAssertion(context =>
            context.User.IsInRole("Admin") ||
            (context.User.IsInRole("Manager") && 
             context.User.HasClaim(c => c.Type == "CanDelete"))));
});

// Sử dụng
[Authorize(Policy = "PremiumUser")]
[HttpGet("premium-content")]
public IActionResult GetPremiumContent() { }

CORS (Cross-Origin Resource Sharing)

Vấn đề

Browser chặn requests từ một domain khác với server (cross-origin requests) vì lý do bảo mật. CORS cho phép server chỉ định origins nào được phép truy cập.

Cấu hình CORS

// Program.cs
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowFrontend", policy =>
    {
        policy.WithOrigins("http://localhost:3000", "https://myapp.com")
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials(); // Chỉ dùng với specific origins
    });
    
    options.AddPolicy("AllowAll", policy =>
    {
        policy.AllowAnyOrigin()
              .AllowAnyHeader()
              .AllowAnyMethod();
    });
});

var app = builder.Build();

app.UseCors("AllowFrontend");

CORS với named policy

[ApiController]
[Route("api/[controller]")]
[EnableCors("AllowFrontend")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok();
    
    [HttpGet]
    [DisableCors] // Disable CORS cho action cụ thể
    public IActionResult GetSecret() => Ok();
}

Preflight Request

┌─────────────────────────────────────────────────────────────────────┐
│                     CORS REQUEST FLOW                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  Browser                                                        │
│      │                                                              │
│      │ 1. OPTIONS /api/products                                  │
│      │    Access-Control-Request-Method: GET                     │
│      │    Access-Control-Request-Headers: Content-Type          │
│      ├────────────────────────────────────────────────────────►   │
│      │◄────────────────────────────────────────────────────────┤  │
│      │ 2. 200 OK                                                 │
│      │    Access-Control-Allow-Origin: http://localhost:3000   │
│      │    Access-Control-Allow-Methods: GET, POST, PUT, DELETE │
│      │    Access-Control-Allow-Headers: Content-Type            │
│      │                                                              │
│      │ 3. GET /api/products                                      │
│      ├────────────────────────────────────────────────────────►   │
│      │◄────────────────────────────────────────────────────────┤  │
│      │ 4. 200 OK                                                 │
│      │    Access-Control-Allow-Origin: http://localhost:3000   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘