auth-service/src/main/java/com/goi/erp/auth/AuthenticationService.java

205 lines
7.6 KiB
Java

package com.goi.erp.auth;
import com.goi.erp.common.exception.InvalidPasswordException;
import com.goi.erp.common.exception.UserNotFoundException;
import com.goi.erp.config.JwtService;
import com.goi.erp.config.SecuritySystemClientsProperties;
import com.goi.erp.employee.Employee;
import com.goi.erp.employee.EmployeeRepository;
import com.goi.erp.employee.EmployeeRole;
import com.goi.erp.employee.EmployeeRoleRepository;
import com.goi.erp.role.RolePermissionRepository;
import com.goi.erp.token.Token;
import com.goi.erp.token.TokenRepository;
import com.goi.erp.token.TokenType;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
@Service
@Transactional
@RequiredArgsConstructor
public class AuthenticationService {
private final EmployeeRepository employeeRepository;
private final EmployeeRoleRepository employeeRoleRepository;
private final RolePermissionRepository rolePermissionRepository;
private final TokenRepository tokenRepository;
private final PasswordEncoder passwordEncoder;
private final JwtService jwtService;
private final SecuritySystemClientsProperties systemClientsProperties;
private final AuthCookieService authCookieService;
private final UserDetailsService userDetailsService;
// ===================== 로그인 =====================
public AuthenticationResponse authenticate(
AuthenticationRequest request,
HttpServletResponse response
) {
Employee employee = employeeRepository.findByEmpLoginId(request.getEmpLoginId())
.orElseThrow(() -> new UserNotFoundException("Employee not found"));
if (!passwordEncoder.matches(request.getEmpLoginPassword(), employee.getEmpLoginPassword())) {
throw new InvalidPasswordException("Invalid password");
}
List<EmployeeRole> activeRoles =
employeeRoleRepository.findActiveRolesByEmployeeId(employee.getEmpId());
List<String> roles = extractRoles(activeRoles);
List<String> permissions = extractPermissions(activeRoles);
String accessToken = jwtService.generateToken(employee, roles, permissions);
String refreshToken = jwtService.generateRefreshToken(employee, roles, permissions);
revokeAllEmployeeTokens(employee);
// refresh 도 저장
saveEmployeeToken(employee, accessToken, TokenType.ACCESS);
saveEmployeeToken(employee, refreshToken, TokenType.REFRESH);
// Cookie로 내려줌
authCookieService.addAuthCookie(response, accessToken);
authCookieService.addRefreshCookie(response, refreshToken);
return AuthenticationResponse.builder()
.authenticated(true)
.loginId(employee.getEmpLoginId())
.firstName(employee.getEmpFirstName())
.lastName(employee.getEmpLastName())
.roles(roles)
.build();
}
// ===================== Refresh Token =====================
public void refreshToken(HttpServletRequest request, HttpServletResponse response) {
String refreshToken = authCookieService
.extractRefreshToken(request)
.orElse(null);
if (refreshToken == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
String loginId = jwtService.extractUsername(refreshToken);
if (loginId == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
UserDetails userDetails = userDetailsService.loadUserByUsername(loginId);
if (!jwtService.isTokenValid(refreshToken, userDetails)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
Employee employee = employeeRepository.findByEmpLoginId(loginId)
.orElseThrow(() -> new UserNotFoundException("Employee not found"));
List<EmployeeRole> activeRoles =
employeeRoleRepository.findActiveRolesByEmployeeId(employee.getEmpId());
List<String> roles = extractRoles(activeRoles);
List<String> permissions = extractPermissions(activeRoles);
String newAccessToken = jwtService.generateToken(employee, roles, permissions);
String newRefreshToken = jwtService.generateRefreshToken(employee, roles, permissions);
// 기존 토큰 전부 revoke
revokeAllEmployeeTokens(employee);
// 새 토큰 저장
saveEmployeeToken(employee, newAccessToken, TokenType.ACCESS);
saveEmployeeToken(employee, newRefreshToken, TokenType.REFRESH);
// 쿠키 갱신
authCookieService.addAuthCookie(response, newAccessToken);
authCookieService.addRefreshCookie(response, newRefreshToken);
// body 없음
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
// ===================== System Token =====================
// OPR / CRM 등 서버간 호출용 (Header 기반)
public SystemAuthenticationResponseDto authenticateSystem(SystemAuthenticationRequestDto request) {
if (request.getClientId() == null || request.getClientSecret() == null) {
throw new InvalidPasswordException("Missing client credentials");
}
var clientConfig = systemClientsProperties.getClients().get(request.getClientId());
if (clientConfig == null) {
throw new InvalidPasswordException("Invalid system client");
}
if (!clientConfig.getSecret().equals(request.getClientSecret())) {
throw new InvalidPasswordException("Invalid system secret");
}
String jwtToken = jwtService.generateSystemToken(
request.getClientId(),
clientConfig.getPermissions()
);
return SystemAuthenticationResponseDto.builder()
.accessToken(jwtToken)
.refreshToken(null)
.build();
}
// ===================== 내부 헬퍼 =====================
private List<String> extractRoles(List<EmployeeRole> roles) {
return roles.stream()
.map(er -> er.getRoleInfo().getRoleName())
.collect(Collectors.toList());
}
private List<String> extractPermissions(List<EmployeeRole> roles) {
return roles.stream()
.flatMap(er -> rolePermissionRepository
.findByRoleId(er.getRoleInfo().getRoleId()).stream())
.map(rp -> rp.getPermissionInfo().getPermModule()
+ ":" + rp.getPermissionInfo().getPermAction()
+ ":" + rp.getPermissionInfo().getPermScope())
.distinct()
.collect(Collectors.toList());
}
private void saveEmployeeToken(Employee employee, String jwtToken, TokenType tokenType) {
Token token = Token.builder()
.employee(employee)
.token(jwtToken)
.tokenType(tokenType)
.expired(false)
.revoked(false)
.build();
tokenRepository.save(token);
}
private void revokeAllEmployeeTokens(Employee employee) {
tokenRepository.revokeAllValidTokensByEmployee(employee.getEmpId());
}
}