package com.caliverse.admin.domain.service; import com.caliverse.admin.domain.dao.admin.AdminMapper; import com.caliverse.admin.domain.dao.admin.TokenMapper; import com.caliverse.admin.domain.entity.Admin; import com.caliverse.admin.domain.entity.STATUS; import com.caliverse.admin.domain.entity.Token; import com.caliverse.admin.domain.request.AuthenticateRequest; import com.caliverse.admin.domain.response.AuthenticateResponse; import com.caliverse.admin.global.common.code.CommonCode; import com.caliverse.admin.global.common.code.ErrorCode; import com.caliverse.admin.global.common.code.SuccessCode; import com.caliverse.admin.global.common.exception.RestApiException; import com.caliverse.admin.global.common.utils.CommonUtils; import com.caliverse.admin.global.configuration.JwtService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.AuthenticationException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; @Slf4j @Service @RequiredArgsConstructor public class AuthenticateService{ private final AdminMapper userMapper; private final TokenMapper tokenMapper; private final AuthenticationManager authenticationManager; private final JwtService jwtService; private final PasswordEncoder passwordEncoder; private final HistoryService historyService; @Value("${password.expiration-days}") private int passwordExpiration; // 로그인 public AuthenticateResponse login(AuthenticateRequest authenticateRequest) { String email = authenticateRequest.getEmail(); String pw = authenticateRequest.getPassword(); // 삭제 계정 여부 if(!userMapper.existsByEmail(email)){ throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_MATCH_USER.getMessage()); } try { authenticationManager.authenticate(new UsernamePasswordAuthenticationToken( email, pw )); }catch (AuthenticationException authException){ // 인증에 실패하면 예외가 발생 AuthenticationException 떨어짐 throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_FOUND_USER.getMessage()); } Admin admin = userMapper.findByEmail(authenticateRequest.getEmail()) .orElseThrow(() -> new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_MATCH_USER.getMessage())); //비번 기간 만료 if (isPasswordExpired(admin.getPwUpdateDt())){ throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.PWD_EXPIRATION.getMessage() +"("+admin.getPwUpdateDt().plus(passwordExpiration,ChronoUnit.DAYS) .atZone(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of("Asia/Seoul")) .format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))+" 종료)"); } if(admin.getStatus().name().equals("ROLE_NOT_PERMITTED") || admin.getStatus().name().equals("REJECT")){ throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_PERMITTED.getMessage()); } int tokenCnt = tokenMapper.getCount(admin.getId()); if(tokenCnt > 1){ tokenMapper.updateResetToken(admin.getId()); } var jwtToken = jwtService.generateToken(admin); var refreshToken = jwtService.generateRefreshToken(admin); revokeAllUserTokens(admin); saveUserToken(admin.getId(), jwtToken); log.info("login id: {}, token: {}", admin.getId(), jwtToken); return AuthenticateResponse.builder() .status(CommonCode.SUCCESS.getHttpStatus()) .result(CommonCode.SUCCESS.getResult()) .authValue(new AuthenticateResponse.AuthValue(jwtToken, refreshToken,String.valueOf(admin.getStatus()))) .build(); } //회원가입 public AuthenticateResponse register(AuthenticateRequest authenticateRequest){ if(userMapper.existsByEmail(authenticateRequest.getEmail())){ throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DUPLICATED_EMAIL.getMessage()); } Admin admin = Admin.builder() // .status(STATUS.ROLE_NOT_PERMITTED) //2024.08.02 즉시 회원가입되게 변경 .groupId((long)2) .status(STATUS.PERMITTED) .name(authenticateRequest.getName()) .email(authenticateRequest.getEmail()) .password(passwordEncoder.encode(authenticateRequest.getPassword())) .build(); userMapper.save(admin); log.info("register Sign Up : {}", admin); return AuthenticateResponse.builder() .status(CommonCode.SUCCESS.getHttpStatus()) .result(CommonCode.SUCCESS.getResult()) .authValue(AuthenticateResponse.AuthValue.builder().message(SuccessCode.SAVE.getMessage()).build()) .build(); } // 토큰 저장 private void saveUserToken(Long memberId, String jwtToken) { var token = Token.builder() .adminId(memberId) .token(jwtToken) .tokenType(Token.TokenType.BEARER) .expired(false) .revoked(false) .build(); tokenMapper.save(token); } //토큰 삭제 private void revokeAllUserTokens(Admin member) { var validUserTokens = tokenMapper.findAllValidTokenByUser(member.getId()).orElse(null); if(validUserTokens!=null){ validUserTokens.setExpired(true); validUserTokens.setRevoked(true); tokenMapper.updateToken(validUserTokens); } } public boolean isPasswordExpired(LocalDateTime lastPasswordChangeDateTime) { LocalDateTime currentDateTime = LocalDateTime.now(); LocalDateTime minusDate = currentDateTime.minusDays(passwordExpiration); boolean isAfter = minusDate.isAfter(lastPasswordChangeDateTime); return isAfter; } }