# Security Patterns - Detailed Reference
Detailed code examples for security patterns in ASP.NET Core.
## Table of Contents
1. [Authentication with Identity](#authentication-with-identity)
2. [JWT Configuration](#jwt-configuration)
3. [Authorization Policies](#authorization-policies)
4. [Password Hashing](#password-hashing)
5. [Two-Factor Authentication](#two-factor-authentication)
6. [Input Validation](#input-validation)
7. [Rate Limiting](#rate-limiting)
8. [Global Exception Handler](#global-exception-handler)
9. [Audit Logging](#audit-logging)
10. [CORS Configuration](#cors-configuration)
---
## Authentication with Identity
### Register User Command Handler
```csharp
///
/// EN: Handler for user registration.
/// VI: Handler cho việc đăng ký user.
///
public class RegisterUserCommandHandler : IRequestHandler
{
private readonly UserManager _userManager;
private readonly ILogger _logger;
public RegisterUserCommandHandler(
UserManager userManager,
ILogger logger)
{
_userManager = userManager;
_logger = logger;
}
public async Task Handle(
RegisterUserCommand request,
CancellationToken cancellationToken)
{
// EN: Check if user exists / VI: Kiểm tra user đã tồn tại
var existingUser = await _userManager.FindByEmailAsync(request.Email);
if (existingUser != null)
{
throw new ConflictException("User with this email already exists");
}
// EN: Create new user / VI: Tạo user mới
var user = new ApplicationUser
{
UserName = request.Email,
Email = request.Email,
FullName = request.FullName,
EmailConfirmed = false
};
// EN: Identity handles password hashing automatically
// VI: Identity tự động hash password
var result = await _userManager.CreateAsync(user, request.Password);
if (!result.Succeeded)
{
var errors = string.Join(", ", result.Errors.Select(e => e.Description));
throw new ValidationException(errors);
}
// EN: Assign default role / VI: Gán role mặc định
await _userManager.AddToRoleAsync(user, "User");
_logger.LogInformation(
"EN: User registered successfully / VI: Đăng ký user thành công: {Email}",
user.Email);
return new RegisterResult(user.Id, user.Email!);
}
}
```
---
## JWT Configuration
### Program.cs Configuration
```csharp
// EN: Configure JWT authentication / VI: Cấu hình JWT authentication
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = builder.Configuration["IdentityServer:Authority"];
options.Audience = builder.Configuration["IdentityServer:Audience"];
options.RequireHttpsMetadata = !builder.Environment.IsDevelopment();
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
var logger = context.HttpContext.RequestServices
.GetRequiredService>();
logger.LogWarning(
"EN: JWT authentication failed / VI: JWT authentication thất bại: {Error}",
context.Exception.Message);
return Task.CompletedTask;
}
};
});
```
---
## Authorization Policies
### Configure Policies
```csharp
// EN: Configure authorization policies / VI: Cấu hình authorization policies
builder.Services.AddAuthorization(options =>
{
// EN: Role-based policy / VI: Policy dựa trên role
options.AddPolicy("AdminOnly", policy =>
policy.RequireRole("Admin"));
// EN: Multiple roles / VI: Nhiều roles
options.AddPolicy("CanManageUsers", policy =>
policy.RequireRole("Admin", "Manager"));
// EN: Claim-based policy / VI: Policy dựa trên claim
options.AddPolicy("PremiumUser", policy =>
policy.RequireClaim("subscription", "premium"));
// EN: Custom requirement / VI: Requirement tùy chỉnh
options.AddPolicy("ResourceOwner", policy =>
policy.AddRequirements(new ResourceOwnerRequirement()));
});
///
/// EN: Custom authorization requirement.
/// VI: Authorization requirement tùy chỉnh.
///
public class ResourceOwnerRequirement : IAuthorizationRequirement { }
public class ResourceOwnerHandler : AuthorizationHandler
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
ResourceOwnerRequirement requirement)
{
var userId = context.User.FindFirst("sub")?.Value;
var resourceOwnerId = context.Resource as string;
if (userId == resourceOwnerId)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
```
---
## Password Hashing
### ASP.NET Core Identity (Automatic)
```csharp
///
/// EN: Identity uses PBKDF2 with HMAC-SHA256 by default.
/// VI: Identity sử dụng PBKDF2 với HMAC-SHA256 mặc định.
///
// EN: Creating user with password (auto-hashed)
// VI: Tạo user với password (tự động hash)
await _userManager.CreateAsync(user, password);
// EN: Verify password / VI: Xác minh password
var isValid = await _userManager.CheckPasswordAsync(user, password);
// EN: Change password / VI: Đổi password
await _userManager.ChangePasswordAsync(user, currentPassword, newPassword);
// EN: Reset password with token / VI: Reset password với token
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
await _userManager.ResetPasswordAsync(user, token, newPassword);
```
### Custom Password Hasher (If Needed)
```csharp
///
/// EN: Configure password hasher options.
/// VI: Cấu hình password hasher options.
///
builder.Services.Configure(options =>
{
// EN: Iteration count (higher = more secure but slower)
// VI: Số lần lặp (cao hơn = bảo mật hơn nhưng chậm hơn)
options.IterationCount = 100000;
});
```
---
## Two-Factor Authentication
### Enable 2FA Command Handler
```csharp
///
/// EN: Handler for enabling 2FA.
/// VI: Handler cho việc bật 2FA.
///
public class Enable2FACommandHandler : IRequestHandler
{
private readonly UserManager _userManager;
private const string AuthenticatorUriFormat =
"otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
public async Task Handle(
Enable2FACommand request,
CancellationToken ct)
{
var user = await _userManager.FindByIdAsync(request.UserId.ToString());
if (user == null)
throw new NotFoundException("User not found");
// EN: Check if 2FA already enabled / VI: Kiểm tra 2FA đã bật chưa
if (await _userManager.GetTwoFactorEnabledAsync(user))
throw new InvalidOperationException("2FA is already enabled");
// EN: Generate authenticator key / VI: Tạo key authenticator
await _userManager.ResetAuthenticatorKeyAsync(user);
var key = await _userManager.GetAuthenticatorKeyAsync(user);
// EN: Generate QR code / VI: Tạo QR code
var uri = string.Format(
AuthenticatorUriFormat,
"GoodGo",
user.Email,
key);
var qrCode = GenerateQrCode(uri);
// EN: Generate recovery codes / VI: Tạo mã khôi phục
var recoveryCodes = await _userManager
.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
return new Enable2FAResult
{
QrCodeBase64 = qrCode,
ManualEntryKey = key!,
RecoveryCodes = recoveryCodes?.ToArray() ?? Array.Empty()
};
}
private string GenerateQrCode(string uri)
{
using var qrGenerator = new QRCodeGenerator();
using var qrData = qrGenerator.CreateQrCode(uri, QRCodeGenerator.ECCLevel.Q);
using var qrCode = new PngByteQRCode(qrData);
var qrBytes = qrCode.GetGraphic(20);
return Convert.ToBase64String(qrBytes);
}
}
```
### Verify 2FA Code
```csharp
///
/// EN: Verify TOTP code during login.
/// VI: Xác minh mã TOTP khi đăng nhập.
///
public async Task VerifyTwoFactorCodeAsync(
ApplicationUser user,
string code)
{
// EN: Verify TOTP code / VI: Xác minh mã TOTP
var isValid = await _userManager
.VerifyTwoFactorTokenAsync(
user,
_userManager.Options.Tokens.AuthenticatorTokenProvider,
code);
if (!isValid)
{
// EN: Try recovery code / VI: Thử mã khôi phục
var result = await _userManager
.RedeemTwoFactorRecoveryCodeAsync(user, code);
return result.Succeeded;
}
return true;
}
```
---
## Input Validation
### FluentValidation Setup
```csharp
// EN: Register FluentValidation / VI: Đăng ký FluentValidation
builder.Services.AddValidatorsFromAssemblyContaining();
builder.Services.AddFluentValidationAutoValidation();
///
/// EN: Validator for register command.
/// VI: Validator cho register command.
///
public class RegisterUserCommandValidator : AbstractValidator
{
public RegisterUserCommandValidator()
{
RuleFor(x => x.Email)
.NotEmpty().WithMessage("Email is required")
.EmailAddress().WithMessage("Invalid email format");
RuleFor(x => x.Password)
.NotEmpty().WithMessage("Password is required")
.MinimumLength(8).WithMessage("Password must be at least 8 characters")
.Matches("[A-Z]").WithMessage("Password must contain uppercase letter")
.Matches("[a-z]").WithMessage("Password must contain lowercase letter")
.Matches("[0-9]").WithMessage("Password must contain digit")
.Matches("[^a-zA-Z0-9]").WithMessage("Password must contain special character");
RuleFor(x => x.FullName)
.MaximumLength(100).WithMessage("Name cannot exceed 100 characters");
}
}
```
---
## Rate Limiting
### ASP.NET Core Rate Limiting
```csharp
// EN: Configure rate limiting / VI: Cấu hình rate limiting
builder.Services.AddRateLimiter(options =>
{
// EN: Standard rate limit / VI: Rate limit chuẩn
options.AddFixedWindowLimiter("standard", opt =>
{
opt.PermitLimit = 100;
opt.Window = TimeSpan.FromMinutes(15);
opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
opt.QueueLimit = 5;
});
// EN: Strict rate limit for sensitive operations
// VI: Rate limit nghiêm ngặt cho operations nhạy cảm
options.AddFixedWindowLimiter("strict", opt =>
{
opt.PermitLimit = 10;
opt.Window = TimeSpan.FromHours(1);
});
// EN: Login rate limit / VI: Rate limit cho login
options.AddSlidingWindowLimiter("login", opt =>
{
opt.PermitLimit = 5;
opt.Window = TimeSpan.FromMinutes(15);
opt.SegmentsPerWindow = 3;
});
options.OnRejected = async (context, token) =>
{
context.HttpContext.Response.StatusCode = 429;
await context.HttpContext.Response.WriteAsJsonAsync(
ApiResponse