feat(backend): Implement password reset flow (Phase 3)

Complete implementation of secure password reset functionality per DAY7-PRD.md specifications.

Changes:
- Domain: PasswordResetToken entity with 1-hour expiration and single-use constraint
- Domain Events: PasswordResetRequestedEvent and PasswordResetCompletedEvent
- Repository: IPasswordResetTokenRepository with token management and invalidation
- Commands: ForgotPasswordCommand and ResetPasswordCommand with handlers
- Security: MemoryRateLimitService (3 requests/hour) and IRateLimitService interface
- API: POST /api/Auth/forgot-password and POST /api/Auth/reset-password endpoints
- Infrastructure: EF Core configuration and database migration for password_reset_tokens table
- Features: Email enumeration prevention, SHA-256 token hashing, refresh token revocation on password reset
- Test: PowerShell test script for password reset flow verification

Security Enhancements:
- Rate limiting: 3 forgot-password requests per hour per email
- Token security: SHA-256 hashing, 1-hour expiration, single-use only
- Privacy: Always return success message to prevent email enumeration
- Audit trail: IP address and User Agent logging for security monitoring
- Session revocation: All refresh tokens revoked after successful password reset

Database:
- New table: password_reset_tokens with indexes for performance
- Columns: id, user_id, token_hash, expires_at, used_at, ip_address, user_agent, created_at

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2025-11-03 21:47:26 +01:00
parent 3dcecc656f
commit 1cf0ef0d9c
19 changed files with 1276 additions and 0 deletions

View File

@@ -38,6 +38,7 @@ public static class DependencyInjection
services.AddScoped<IRefreshTokenRepository, RefreshTokenRepository>();
services.AddScoped<IUserTenantRoleRepository, UserTenantRoleRepository>();
services.AddScoped<IEmailVerificationTokenRepository, EmailVerificationTokenRepository>();
services.AddScoped<IPasswordResetTokenRepository, PasswordResetTokenRepository>();
// Application Services
services.AddScoped<IJwtService, JwtService>();
@@ -45,6 +46,10 @@ public static class DependencyInjection
services.AddScoped<IRefreshTokenService, RefreshTokenService>();
services.AddScoped<ISecurityTokenService, SecurityTokenService>();
// Memory cache for rate limiting
services.AddMemoryCache();
services.AddSingleton<IRateLimitService, MemoryRateLimitService>();
// Email Services
var emailProvider = configuration["Email:Provider"] ?? "Mock";
if (emailProvider.Equals("Mock", StringComparison.OrdinalIgnoreCase))