관리자 관리수정, 에러코드 공통 추가

This commit is contained in:
2025-12-11 12:27:20 +09:00
parent 2b38a317ba
commit ed0159edda
16 changed files with 222 additions and 133 deletions

View File

@@ -1,31 +0,0 @@
package com.kamco.cd.kamcoback.auth;
import com.kamco.cd.kamcoback.members.service.AuthService;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class AuthFailureEventListener implements ApplicationListener<AbstractAuthenticationFailureEvent> {
private final AuthService authService;
@Override
public void onApplicationEvent(AbstractAuthenticationFailureEvent event) {
// 로그인 시도에 사용된 (username)
Object principal = event.getAuthentication().getPrincipal();
if (principal instanceof String username) {
// 로그인 실패 카운트 증가 로직 호출
authService.loginFail(UUID.fromString(username));
}
}
@Override
public boolean supportsAsyncExecution() {
return ApplicationListener.super.supportsAsyncExecution();
}
}

View File

@@ -1,11 +1,13 @@
package com.kamco.cd.kamcoback.auth; package com.kamco.cd.kamcoback.auth;
import com.kamco.cd.kamcoback.common.enums.error.AuthErrorCode;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; import com.kamco.cd.kamcoback.postgres.entity.MemberEntity;
import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository; import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository;
import java.time.ZonedDateTime;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.mindrot.jbcrypt.BCrypt; import org.mindrot.jbcrypt.BCrypt;
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
@@ -28,14 +30,34 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
MemberEntity member = MemberEntity member =
membersRepository membersRepository
.findByUserId(username) .findByUserId(username)
.orElseThrow(() -> new BadCredentialsException("ID 또는 비밀번호가 일치하지 않습니다.")); .orElseThrow(() -> new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND));
// 2. jBCrypt + 커스텀 salt 로 저장된 패스워드 비교 // 2. jBCrypt + 커스텀 salt 로 저장된 패스워드 비교
if (!BCrypt.checkpw(rawPassword, member.getPassword())) { if (!BCrypt.checkpw(rawPassword, member.getPassword())) {
throw new BadCredentialsException("ID 또는 비밀번호가 일치하지 않습니다."); // 실패 카운트 저장
int cnt = member.getLoginFailCount() + 1;
if (cnt >= 5) {
member.setStatus("INACTIVE");
}
member.setLoginFailCount(cnt);
membersRepository.save(member);
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
} }
// 3. 인증 성공 → UserDetails 생성 // 3. 패스워드 실패 횟수 체크
if (member.getLoginFailCount() >= 5) {
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_EXCEEDED);
}
// 4. 인증 성공 로그인 시간 저장
if (member.getFirstLoginDttm() == null) {
member.setFirstLoginDttm(ZonedDateTime.now());
}
member.setLastLoginDttm(ZonedDateTime.now());
member.setLoginFailCount(0);
membersRepository.save(member);
// 5. 인증 성공 → UserDetails 생성
CustomUserDetails userDetails = new CustomUserDetails(member); CustomUserDetails userDetails = new CustomUserDetails(member);
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

View File

@@ -7,7 +7,7 @@ import lombok.Getter;
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum RoleType implements EnumType { public enum RoleType implements EnumType {
ROLE_ADMIN("시스템 관리자"), ROLE_ADMIN("관리자"),
ROLE_LABELER("라벨러"), ROLE_LABELER("라벨러"),
ROLE_REVIEWER("검수자"); ROLE_REVIEWER("검수자");
@@ -22,4 +22,13 @@ public enum RoleType implements EnumType {
public String getText() { public String getText() {
return desc; return desc;
} }
public static RoleType from(String value) {
for (RoleType type : values()) {
if (type.name().equalsIgnoreCase(value)) {
return type;
}
}
return null;
}
} }

View File

@@ -0,0 +1,25 @@
package com.kamco.cd.kamcoback.common.enums;
import com.kamco.cd.kamcoback.config.enums.EnumType;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum StatusType implements EnumType {
ACTIVE("활성"),
INACTIVE("비활성"),
ARCHIVED("탈퇴");
private final String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}

View File

@@ -0,0 +1,30 @@
package com.kamco.cd.kamcoback.common.enums.error;
import com.kamco.cd.kamcoback.common.utils.ErrorCode;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Getter
public enum AuthErrorCode implements ErrorCode {
// 🔐 로그인 관련
LOGIN_ID_NOT_FOUND(
"LOGIN_ID_NOT_FOUND",
HttpStatus.UNAUTHORIZED),
LOGIN_PASSWORD_MISMATCH(
"LOGIN_PASSWORD_MISMATCH",
HttpStatus.UNAUTHORIZED),
LOGIN_PASSWORD_EXCEEDED(
"LOGIN_PASSWORD_EXCEEDED",
HttpStatus.UNAUTHORIZED);
private final String code;
private final HttpStatus status;
AuthErrorCode(String code, HttpStatus status) {
this.code = code;
this.status = status;
}
}

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.common.exception; package com.kamco.cd.kamcoback.common.exception;
import com.kamco.cd.kamcoback.common.utils.ErrorCode;
import lombok.Getter; import lombok.Getter;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@@ -19,4 +20,9 @@ public class CustomApiException extends RuntimeException {
this.codeName = codeName; this.codeName = codeName;
this.status = status; this.status = status;
} }
public CustomApiException(ErrorCode errorCode) {
this.codeName = errorCode.getCode();
this.status = errorCode.getStatus();
}
} }

View File

@@ -0,0 +1,10 @@
package com.kamco.cd.kamcoback.common.utils;
import org.springframework.http.HttpStatus;
public interface ErrorCode {
String getCode();
HttpStatus getStatus();
}

View File

@@ -6,12 +6,14 @@ import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@@ -40,21 +42,21 @@ public class SecurityConfig {
customAuthenticationProvider) // 로그인 패스워드 비교방식 스프링 기본 Provider 사용안함 커스텀 사용 customAuthenticationProvider) // 로그인 패스워드 비교방식 스프링 기본 Provider 사용안함 커스텀 사용
.authorizeHttpRequests( .authorizeHttpRequests(
auth -> auth ->
auth.anyRequest().permitAll()); auth.requestMatchers(HttpMethod.OPTIONS, "/**")
// requestMatchers(HttpMethod.OPTIONS, "/**") .permitAll() // preflight 허용
// .permitAll() // preflight 허용 .requestMatchers(
// .requestMatchers( "/api/auth/signin",
// "/api/auth/signin", "/api/auth/refresh",
// "/api/auth/refresh", "/swagger-ui/**",
// "/swagger-ui/**", "/api/members/{memberId}/password",
// "/v3/api-docs/**") "/v3/api-docs/**")
// .permitAll() .permitAll()
// .anyRequest() .anyRequest()
// .authenticated()) .authenticated())
// .addFilterBefore( .addFilterBefore(
// jwtAuthenticationFilter, jwtAuthenticationFilter,
// UsernamePasswordAuthenticationFilter UsernamePasswordAuthenticationFilter
// .class) // 요청 들어오면 먼저 JWT 토큰 검사 후 security context 에 사용자 정보 저장. .class) // 요청 들어오면 먼저 JWT 토큰 검사 후 security context 에 사용자 정보 저장.
; ;
return http.build(); return http.build();

View File

@@ -20,9 +20,11 @@ public class ApiResponseDto<T> {
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
private T errorData; private T errorData;
@JsonIgnore private HttpStatus httpStatus; @JsonIgnore
private HttpStatus httpStatus;
@JsonIgnore private Long errorLogUid; @JsonIgnore
private Long errorLogUid;
public ApiResponseDto(T data) { public ApiResponseDto(T data) {
this.data = data; this.data = data;
@@ -114,7 +116,9 @@ public class ApiResponseDto<T> {
} }
} }
/** Error가 아닌 Business상 성공이거나 실패인 경우, 메세지 함께 전달하기 위한 object */ /**
* Error가 아닌 Business상 성공이거나 실패인 경우, 메세지 함께 전달하기 위한 object
*/
@Getter @Getter
public static class ResponseObj { public static class ResponseObj {
@@ -164,6 +168,9 @@ public class ApiResponseDto<T> {
NOT_FOUND_USER_FOR_EMAIL("이메일로 유저를 찾을 수 없습니다."), NOT_FOUND_USER_FOR_EMAIL("이메일로 유저를 찾을 수 없습니다."),
NOT_FOUND_USER("사용자를 찾을 수 없습니다."), NOT_FOUND_USER("사용자를 찾을 수 없습니다."),
UNPROCESSABLE_ENTITY("이 데이터는 삭제할 수 없습니다."), UNPROCESSABLE_ENTITY("이 데이터는 삭제할 수 없습니다."),
LOGIN_ID_NOT_FOUND("아이디를 잘못 입력하셨습니다."),
LOGIN_PASSWORD_MISMATCH("비밀번호를 잘못 입력하셨습니다."),
LOGIN_PASSWORD_EXCEEDED("비밀번호 오류 횟수를 초과하여 이용하실 수 없습니다.\n로그인 오류에 대해 관리자에게 문의하시기 바랍니다."),
INVALID_EMAIL_TOKEN( INVALID_EMAIL_TOKEN(
"You can only reset your password within 24 hours from when the email was sent.\n" "You can only reset your password within 24 hours from when the email was sent.\n"
+ "To reset your password again, please submit a new request through \"Forgot" + "To reset your password again, please submit a new request through \"Forgot"

View File

@@ -5,4 +5,17 @@ public interface EnumType {
String getId(); String getId();
String getText(); String getText();
// code로 text
static <E extends Enum<E> & EnumType> E fromId(Class<E> enumClass, String id) {
if (id == null) {
return null;
}
for (E e : enumClass.getEnumConstants()) {
if (id.equalsIgnoreCase(e.getId())) {
return e;
}
}
return null; // 못 찾으면 null
}
} }

View File

@@ -7,6 +7,7 @@ import com.kamco.cd.kamcoback.members.dto.SignInRequest;
import com.kamco.cd.kamcoback.members.service.AuthService; import com.kamco.cd.kamcoback.members.service.AuthService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.responses.ApiResponses;
@@ -14,7 +15,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.nio.file.AccessDeniedException; import java.nio.file.AccessDeniedException;
import java.time.Duration; import java.time.Duration;
import java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
@@ -55,12 +55,43 @@ public class AuthController {
content = @Content(schema = @Schema(implementation = TokenResponse.class))), content = @Content(schema = @Schema(implementation = TokenResponse.class))),
@ApiResponse( @ApiResponse(
responseCode = "401", responseCode = "401",
description = "ID 또는 비밀번호 불일치", description = "로그인 실패 (아이디/비밀번호 오류, 계정잠금 등)",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))), content =
@ApiResponse( @Content(
responseCode = "400", schema = @Schema(implementation = ErrorResponse.class),
description = "미사용 상태", examples = {
content = @Content(schema = @Schema(implementation = ErrorResponse.class))) @ExampleObject(
name = "아이디 입력 오류",
description = "존재하지 않는 아이디",
value = """
{
"code": "LOGIN_ID_NOT_FOUND",
"message": "아이디를 잘못 입력하셨습니다.",
"detail": null
}
"""),
@ExampleObject(
name = "비밀번호 입력 오류 (4회 이하)",
description = "아이디는 정상, 비밀번호를 여러 번 틀린 경우",
value = """
{
"code": "LOGIN_PASSWORD_MISMATCH",
"message": "비밀번호를 잘못 입력하셨습니다.",
"detail": "비밀번호 입력 오류 3회, 2회 남았습니다."
}
"""),
@ExampleObject(
name = "비밀번호 오류 횟수 초과",
description = "비밀번호 5회 이상 오류로 계정 잠김",
value = """
{
"code": "LOGIN_PASSWORD_EXCEEDED",
"message": "비밀번호 오류 횟수를 초과하여 이용하실 수 없습니다.",
"detail": "로그인 오류에 대해 관리자에게 문의하시기 바랍니다."
}
""")
}
))
}) })
public ApiResponseDto<TokenResponse> signin( public ApiResponseDto<TokenResponse> signin(
@io.swagger.v3.oas.annotations.parameters.RequestBody( @io.swagger.v3.oas.annotations.parameters.RequestBody(
@@ -75,15 +106,14 @@ public class AuthController {
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())); new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
String status = authService.getUserStatus(request); String status = authService.getUserStatus(request);
if ("INACTIVE".equals(status)) {
// INACTIVE 비활성 상태(새로운 패스워드 입력 해야함), ARCHIVED 탈퇴
if (!"ACTIVE".equals(status)) {
return ApiResponseDto.ok(new TokenResponse(status, null, null)); return ApiResponseDto.ok(new TokenResponse(status, null, null));
} }
String username = authentication.getName(); // UserDetailsService 에서 사용한 username String username = authentication.getName(); // UserDetailsService 에서 사용한 username
// 로그인 시간 저장
authService.saveLogin(UUID.fromString(username));
String accessToken = jwtTokenProvider.createAccessToken(username); String accessToken = jwtTokenProvider.createAccessToken(username);
String refreshToken = jwtTokenProvider.createRefreshToken(username); String refreshToken = jwtTokenProvider.createRefreshToken(username);

View File

@@ -64,7 +64,7 @@ public class MembersApiController {
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@PatchMapping("/{memberId}/password") @PatchMapping("/{memberId}/password")
public ApiResponseDto<Long> resetPassword(@PathVariable Long memberId, @RequestBody @Valid MembersDto.InitReq initReq) { public ApiResponseDto<String> resetPassword(@PathVariable String memberId, @RequestBody @Valid MembersDto.InitReq initReq) {
membersService.resetPassword(memberId, initReq); membersService.resetPassword(memberId, initReq);
return ApiResponseDto.createOK(memberId); return ApiResponseDto.createOK(memberId);
} }

View File

@@ -1,6 +1,9 @@
package com.kamco.cd.kamcoback.members.dto; package com.kamco.cd.kamcoback.members.dto;
import com.kamco.cd.kamcoback.common.enums.RoleType;
import com.kamco.cd.kamcoback.common.enums.StatusType;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import com.kamco.cd.kamcoback.config.enums.EnumType;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@@ -22,11 +25,13 @@ public class MembersDto {
private Long id; private Long id;
private UUID uuid; private UUID uuid;
private String userRole; private String userRole;
private String userRoleName;
private String name; private String name;
private String userId; private String userId;
private String employeeNo; private String employeeNo;
private String tempPassword; private String tempPassword;
private String status; private String status;
private String statusName;
@JsonFormatDttm @JsonFormatDttm
private ZonedDateTime createdDttm; private ZonedDateTime createdDttm;
@JsonFormatDttm @JsonFormatDttm
@@ -40,11 +45,13 @@ public class MembersDto {
Long id, Long id,
UUID uuid, UUID uuid,
String userRole, String userRole,
String userRoleName,
String name, String name,
String userId, String userId,
String employeeNo, String employeeNo,
String tempPassword, String tempPassword,
String status, String status,
String statusName,
ZonedDateTime createdDttm, ZonedDateTime createdDttm,
ZonedDateTime updatedDttm, ZonedDateTime updatedDttm,
ZonedDateTime firstLoginDttm, ZonedDateTime firstLoginDttm,
@@ -53,16 +60,29 @@ public class MembersDto {
this.id = id; this.id = id;
this.uuid = uuid; this.uuid = uuid;
this.userRole = userRole; this.userRole = userRole;
this.userRoleName = getUserRoleName(userRole);
this.name = name; this.name = name;
this.userId = userId; this.userId = userId;
this.employeeNo = employeeNo; this.employeeNo = employeeNo;
this.tempPassword = tempPassword; this.tempPassword = tempPassword;
this.status = status; this.status = status;
this.statusName = getStatusName(status);
this.createdDttm = createdDttm; this.createdDttm = createdDttm;
this.updatedDttm = updatedDttm; this.updatedDttm = updatedDttm;
this.firstLoginDttm = firstLoginDttm; this.firstLoginDttm = firstLoginDttm;
this.lastLoginDttm = lastLoginDttm; this.lastLoginDttm = lastLoginDttm;
} }
private String getUserRoleName(String roleId) {
RoleType type = EnumType.fromId(RoleType.class, roleId);
return type.getText();
}
private String getStatusName(String status) {
StatusType type = EnumType.fromId(StatusType.class, status);
return type.getText();
}
} }
@Getter @Getter

View File

@@ -2,7 +2,6 @@ package com.kamco.cd.kamcoback.members.service;
import com.kamco.cd.kamcoback.members.dto.SignInRequest; import com.kamco.cd.kamcoback.members.dto.SignInRequest;
import com.kamco.cd.kamcoback.postgres.core.MembersCoreService; import com.kamco.cd.kamcoback.postgres.core.MembersCoreService;
import java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -14,26 +13,6 @@ public class AuthService {
private final MembersCoreService membersCoreService; private final MembersCoreService membersCoreService;
/**
* 로그인 일시 저장
*
* @param uuid
*/
@Transactional
public void saveLogin(UUID uuid) {
membersCoreService.saveLogin(uuid);
}
/**
* 로그인 실패 저장
*
* @param uuid
*/
@Transactional
public void loginFail(UUID uuid) {
membersCoreService.loginFail(uuid);
}
/** /**
* 사용자 상태 조회 * 사용자 상태 조회
* *

View File

@@ -35,7 +35,7 @@ public class MembersService {
* @param initReq * @param initReq
*/ */
@Transactional @Transactional
public void resetPassword(Long id, MembersDto.InitReq initReq) { public void resetPassword(String id, MembersDto.InitReq initReq) {
if (!isValidPassword(initReq.getPassword())) { if (!isValidPassword(initReq.getPassword())) {
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST); throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
} }
@@ -49,7 +49,8 @@ public class MembersService {
* @return * @return
*/ */
private boolean isValidPassword(String password) { private boolean isValidPassword(String password) {
String regex = "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[!@#$]).{8,20}$"; String passwordPattern =
return Pattern.matches(regex, password); "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-\\[\\]{};':\"\\\\|,.<>/?]).{8,20}$";
return Pattern.matches(passwordPattern, password);
} }
} }

View File

@@ -1,6 +1,8 @@
package com.kamco.cd.kamcoback.postgres.core; package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator; import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator;
import com.kamco.cd.kamcoback.common.enums.error.AuthErrorCode;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.members.dto.MembersDto; import com.kamco.cd.kamcoback.members.dto.MembersDto;
import com.kamco.cd.kamcoback.members.dto.MembersDto.AddReq; import com.kamco.cd.kamcoback.members.dto.MembersDto.AddReq;
import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic; import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic;
@@ -8,7 +10,6 @@ import com.kamco.cd.kamcoback.members.dto.SignInRequest;
import com.kamco.cd.kamcoback.members.exception.MemberException.DuplicateMemberException; import com.kamco.cd.kamcoback.members.exception.MemberException.DuplicateMemberException;
import com.kamco.cd.kamcoback.members.exception.MemberException.DuplicateMemberException.Field; import com.kamco.cd.kamcoback.members.exception.MemberException.DuplicateMemberException.Field;
import com.kamco.cd.kamcoback.members.exception.MemberException.MemberNotFoundException; import com.kamco.cd.kamcoback.members.exception.MemberException.MemberNotFoundException;
import com.kamco.cd.kamcoback.members.exception.MemberException.PasswordNotFoundException;
import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; import com.kamco.cd.kamcoback.postgres.entity.MemberEntity;
import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository; import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@@ -99,12 +100,12 @@ public class MembersCoreService {
* *
* @param id * @param id
*/ */
public void resetPassword(Long id, MembersDto.InitReq initReq) { public void resetPassword(String id, MembersDto.InitReq initReq) {
MemberEntity memberEntity = MemberEntity memberEntity =
membersRepository.findById(id).orElseThrow(() -> new MemberNotFoundException()); membersRepository.findByUserId(id).orElseThrow(() -> new MemberNotFoundException());
if (!memberEntity.getTempPassword().equals(initReq.getTempPassword())) { if (!memberEntity.getTempPassword().equals(initReq.getTempPassword())) {
throw new PasswordNotFoundException(); throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
} }
String salt = String salt =
@@ -129,41 +130,6 @@ public class MembersCoreService {
return membersRepository.findByMembers(searchReq); return membersRepository.findByMembers(searchReq);
} }
/**
* 최초 로그인 저장 마지막 로그인 저장
*
* @param uuid
*/
public void saveLogin(UUID uuid) {
MemberEntity memberEntity =
membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());
if (memberEntity.getFirstLoginDttm() == null) {
memberEntity.setFirstLoginDttm(ZonedDateTime.now());
}
memberEntity.setLastLoginDttm(ZonedDateTime.now());
memberEntity.setLoginFailCount(0);
membersRepository.save(memberEntity);
}
/**
* 로그인 실패시 상태 저장
*
* @param uuid
*/
public void loginFail(UUID uuid) {
MemberEntity memberEntity =
membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());
int failCnt = memberEntity.getLoginFailCount() + 1;
if (failCnt >= 5) {
memberEntity.setStatus("INACTIVE");
}
memberEntity.setLoginFailCount(failCnt);
membersRepository.save(memberEntity);
}
/** /**
* 사용자 상태 조회 * 사용자 상태 조회
* *