Files
CompanyRegister/backend/src/main/java/com/smartoffice/auth/AuthService.java
2026-01-28 23:56:33 +08:00

103 lines
4.4 KiB
Java

package com.smartoffice.auth;
import com.smartoffice.common.ApiException;
import com.smartoffice.user.Role;
import com.smartoffice.user.User;
import com.smartoffice.user.UserDto;
import com.smartoffice.user.UserRepository;
import com.smartoffice.user.UserStatus;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.time.Instant;
@Service
public class AuthService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final AuthenticationManager authenticationManager;
private final JwtService jwtService;
private final int maxAttempts;
private final int lockMinutes;
public AuthService(UserRepository userRepository,
PasswordEncoder passwordEncoder,
AuthenticationManager authenticationManager,
JwtService jwtService,
@Value("${app.security.lockout.max-attempts}") int maxAttempts,
@Value("${app.security.lockout.lock-minutes}") int lockMinutes) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.authenticationManager = authenticationManager;
this.jwtService = jwtService;
this.maxAttempts = maxAttempts;
this.lockMinutes = lockMinutes;
}
@Transactional
public AuthResponse login(LoginRequest request) {
User user = userRepository.findByUsername(request.getUsername())
.orElseThrow(() -> new ApiException(401, "Invalid credentials"));
if (user.getStatus() == UserStatus.DISABLED) {
throw new ApiException(403, "Account disabled");
}
if (user.getLockedUntil() != null && user.getLockedUntil().isAfter(Instant.now())) {
throw new ApiException(423, "Account locked until " + user.getLockedUntil());
}
if (user.getStatus() == UserStatus.LOCKED && user.getLockedUntil() == null) {
throw new ApiException(423, "Account locked");
}
if (user.getLockedUntil() != null && user.getLockedUntil().isBefore(Instant.now())) {
user.setLockedUntil(null);
user.setStatus(UserStatus.ACTIVE);
user.setFailedLoginAttempts(0);
userRepository.save(user);
}
try {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
user.setFailedLoginAttempts(0);
user.setLockedUntil(null);
user.setLastLoginAt(Instant.now());
user.setStatus(UserStatus.ACTIVE);
userRepository.save(user);
String token = jwtService.generateToken(principal);
return new AuthResponse(token, UserDto.from(user));
} catch (Exception ex) {
int attempts = user.getFailedLoginAttempts() + 1;
user.setFailedLoginAttempts(attempts);
if (attempts >= maxAttempts) {
user.setLockedUntil(Instant.now().plusSeconds(lockMinutes * 60L));
user.setStatus(UserStatus.LOCKED);
}
userRepository.save(user);
throw new ApiException(401, "Invalid credentials");
}
}
@Transactional
public UserDto register(RegisterRequest request) {
if (userRepository.existsByUsername(request.getUsername())) {
throw new ApiException(409, "Username already exists");
}
User user = new User();
user.setUsername(request.getUsername());
user.setPasswordHash(passwordEncoder.encode(request.getPassword()));
user.setFullName(request.getFullName());
user.setEmail(request.getEmail());
user.setPhone(request.getPhone());
user.setRole(Role.EMPLOYEE);
user.setStatus(UserStatus.ACTIVE);
userRepository.save(user);
return UserDto.from(user);
}
}