100 lines
3.6 KiB
C#
100 lines
3.6 KiB
C#
using ColaFlow.Modules.Identity.Application.Dtos;
|
|
using ColaFlow.Modules.Identity.Application.Services;
|
|
using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants;
|
|
using ColaFlow.Modules.Identity.Domain.Aggregates.Users;
|
|
using ColaFlow.Modules.Identity.Domain.Repositories;
|
|
using MediatR;
|
|
|
|
namespace ColaFlow.Modules.Identity.Application.Commands.Login;
|
|
|
|
public class LoginCommandHandler(
|
|
ITenantRepository tenantRepository,
|
|
IUserRepository userRepository,
|
|
IJwtService jwtService,
|
|
IPasswordHasher passwordHasher,
|
|
IRefreshTokenService refreshTokenService,
|
|
IUserTenantRoleRepository userTenantRoleRepository)
|
|
: IRequestHandler<LoginCommand, LoginResponseDto>
|
|
{
|
|
public async Task<LoginResponseDto> Handle(LoginCommand request, CancellationToken cancellationToken)
|
|
{
|
|
// 1. Find tenant
|
|
var slug = TenantSlug.Create(request.TenantSlug);
|
|
var tenant = await tenantRepository.GetBySlugAsync(slug, cancellationToken);
|
|
if (tenant == null)
|
|
{
|
|
throw new UnauthorizedAccessException("Invalid credentials");
|
|
}
|
|
|
|
// 2. Find user
|
|
var email = Email.Create(request.Email);
|
|
var user = await userRepository.GetByEmailAsync(TenantId.Create(tenant.Id), email, cancellationToken);
|
|
if (user == null)
|
|
{
|
|
throw new UnauthorizedAccessException("Invalid credentials");
|
|
}
|
|
|
|
// 3. Verify password
|
|
if (string.IsNullOrEmpty(user.PasswordHash) || !passwordHasher.VerifyPassword(request.Password, user.PasswordHash))
|
|
{
|
|
throw new UnauthorizedAccessException("Invalid credentials");
|
|
}
|
|
|
|
// 4. Get user's tenant role
|
|
var userTenantRole = await userTenantRoleRepository.GetByUserAndTenantAsync(
|
|
user.Id,
|
|
tenant.Id,
|
|
cancellationToken);
|
|
|
|
if (userTenantRole is null)
|
|
{
|
|
throw new InvalidOperationException($"User {user.Id} has no role assigned for tenant {tenant.Id}");
|
|
}
|
|
|
|
// 5. Generate JWT token with role
|
|
var accessToken = jwtService.GenerateToken(user, tenant, userTenantRole.Role);
|
|
|
|
// 6. Generate refresh token
|
|
var refreshToken = await refreshTokenService.GenerateRefreshTokenAsync(
|
|
user,
|
|
ipAddress: null,
|
|
userAgent: null,
|
|
cancellationToken);
|
|
|
|
// 7. Update last login time
|
|
user.RecordLogin();
|
|
await userRepository.UpdateAsync(user, cancellationToken);
|
|
|
|
// 8. Return result
|
|
return new LoginResponseDto
|
|
{
|
|
User = new UserDto
|
|
{
|
|
Id = user.Id,
|
|
TenantId = tenant.Id,
|
|
Email = user.Email.Value,
|
|
FullName = user.FullName.Value,
|
|
Status = user.Status.ToString(),
|
|
AuthProvider = user.AuthProvider.ToString(),
|
|
IsEmailVerified = user.EmailVerifiedAt.HasValue,
|
|
LastLoginAt = user.LastLoginAt,
|
|
CreatedAt = user.CreatedAt
|
|
},
|
|
Tenant = new TenantDto
|
|
{
|
|
Id = tenant.Id,
|
|
Name = tenant.Name.Value,
|
|
Slug = tenant.Slug.Value,
|
|
Status = tenant.Status.ToString(),
|
|
Plan = tenant.Plan.ToString(),
|
|
SsoEnabled = tenant.SsoConfig != null,
|
|
SsoProvider = tenant.SsoConfig?.Provider.ToString(),
|
|
CreatedAt = tenant.CreatedAt,
|
|
UpdatedAt = tenant.UpdatedAt ?? tenant.CreatedAt
|
|
},
|
|
AccessToken = accessToken,
|
|
RefreshToken = refreshToken
|
|
};
|
|
}
|
|
}
|