diff --git a/src/main/java/com/kamco/cd/kamcoback/auth/CustomAuthenticationProvider.java b/src/main/java/com/kamco/cd/kamcoback/auth/CustomAuthenticationProvider.java index c89f793e..36260107 100644 --- a/src/main/java/com/kamco/cd/kamcoback/auth/CustomAuthenticationProvider.java +++ b/src/main/java/com/kamco/cd/kamcoback/auth/CustomAuthenticationProvider.java @@ -6,9 +6,11 @@ import lombok.RequiredArgsConstructor; import org.mindrot.jbcrypt.BCrypt; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Component; @Component @@ -16,6 +18,7 @@ import org.springframework.stereotype.Component; public class CustomAuthenticationProvider implements AuthenticationProvider { private final MembersRepository membersRepository; + private final UserDetailsService userDetailsService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { @@ -24,9 +27,9 @@ public class CustomAuthenticationProvider implements AuthenticationProvider { // 1. 유저 조회 MemberEntity member = - membersRepository - .findByUserId(username) - .orElseThrow(() -> new BadCredentialsException("ID 또는 비밀번호가 일치하지 않습니다.")); + membersRepository + .findByUserId(username) + .orElseThrow(() -> new BadCredentialsException("ID 또는 비밀번호가 일치하지 않습니다.")); // 2. jBCrypt + 커스텀 salt 로 저장된 패스워드 비교 if (!BCrypt.checkpw(rawPassword, member.getPassword())) { @@ -36,6 +39,11 @@ public class CustomAuthenticationProvider implements AuthenticationProvider { // 3. 인증 성공 → UserDetails 생성 CustomUserDetails userDetails = new CustomUserDetails(member); + // 4. 상태값 확인 + if (!userDetails.isEnabled()) { + throw new DisabledException("비활성화된 계정입니다."); + } + return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); } diff --git a/src/main/java/com/kamco/cd/kamcoback/auth/CustomUserDetails.java b/src/main/java/com/kamco/cd/kamcoback/auth/CustomUserDetails.java index b65be3f0..8efb073a 100644 --- a/src/main/java/com/kamco/cd/kamcoback/auth/CustomUserDetails.java +++ b/src/main/java/com/kamco/cd/kamcoback/auth/CustomUserDetails.java @@ -46,7 +46,7 @@ public class CustomUserDetails implements UserDetails { @Override public boolean isEnabled() { - return member.getStatus().equalsIgnoreCase("ACTIVE"); + return "ACTIVE".equals(member.getStatus()); } public MemberEntity getMember() { diff --git a/src/main/java/com/kamco/cd/kamcoback/members/AuthController.java b/src/main/java/com/kamco/cd/kamcoback/members/AuthController.java index d14a9a4a..28877c5e 100644 --- a/src/main/java/com/kamco/cd/kamcoback/members/AuthController.java +++ b/src/main/java/com/kamco/cd/kamcoback/members/AuthController.java @@ -56,6 +56,10 @@ public class AuthController { @ApiResponse( responseCode = "401", description = "ID 또는 비밀번호 불일치", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "400", + description = "미사용 상태", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) }) public ApiResponseDto signin( @@ -65,6 +69,12 @@ public class AuthController { @RequestBody SignInRequest request, HttpServletResponse response) { + + // + if (authService.existsUsername(request)) { +// return + } + Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())); diff --git a/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java b/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java index bfcdc221..6f63553c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java @@ -49,12 +49,12 @@ public class MembersApiController { } - @Operation(summary = "비밀번호 초기화", description = "비밀번호 초기화") + @Operation(summary = "사용자 비밀번호 변경", description = "사용자 비밀번호 변경") @ApiResponses( value = { @ApiResponse( responseCode = "201", - description = "비밀번호 초기화", + description = "사용자 비밀번호 변경", content = @Content( mediaType = "application/json", diff --git a/src/main/java/com/kamco/cd/kamcoback/members/dto/MemberDetails.java b/src/main/java/com/kamco/cd/kamcoback/members/dto/MemberDetails.java deleted file mode 100644 index 9c1b06f4..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/members/dto/MemberDetails.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.kamco.cd.kamcoback.members.dto; - -import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; -import java.util.Collection; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -@RequiredArgsConstructor -public class MemberDetails implements UserDetails { - - private final MemberEntity member; - - @Override - public Collection getAuthorities() { - // TODO: tb_member_role 에서 역할 꺼내서 권한으로 변환하고 싶으면 여기 구현 - // 예시 (나중에 MemberRoleEntity 보고 수정): - // return member.getTbMemberRoles().stream() - // .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getRoleName())) - // .toList(); - - return List.of(); // 일단 빈 권한 리스트 - } - - @Override - public String getPassword() { - return member.getPassword(); // 암호화된 비밀번호 - } - - @Override - public String getUsername() { - // 로그인 ID 로 무엇을 쓸지 선택 - // 1) 이메일 로그인: - return member.getUserId(); - - // 2) 사번으로 로그인하고 싶으면: - // return member.getEmployeeNo(); - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - // status 가 ACTIVE 일 때만 로그인 허용 - return "ACTIVE".equalsIgnoreCase(member.getStatus()); - } - - public MemberEntity getMember() { - return member; - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java b/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java index af052366..d28d39ca 100644 --- a/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java @@ -151,8 +151,13 @@ public class MembersDto { @Setter public static class InitReq { - @Schema(description = "패스워드", example = "") + @Schema(description = "변경 패스워드", example = "") @Size(max = 255) + @NotBlank private String password; + + @Schema(description = "초기 패스워드", example = "") + @NotBlank + private String tempPassword; } } diff --git a/src/main/java/com/kamco/cd/kamcoback/members/exception/MemberException.java b/src/main/java/com/kamco/cd/kamcoback/members/exception/MemberException.java index b8dce363..33d2e8da 100644 --- a/src/main/java/com/kamco/cd/kamcoback/members/exception/MemberException.java +++ b/src/main/java/com/kamco/cd/kamcoback/members/exception/MemberException.java @@ -35,4 +35,15 @@ public class MemberException { super(message); } } + + public static class PasswordNotFoundException extends RuntimeException { + + public PasswordNotFoundException() { + super("Password not found"); + } + + public PasswordNotFoundException(String message) { + super(message); + } + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/members/service/AuthService.java b/src/main/java/com/kamco/cd/kamcoback/members/service/AuthService.java index 49ce1bce..065c7aaa 100644 --- a/src/main/java/com/kamco/cd/kamcoback/members/service/AuthService.java +++ b/src/main/java/com/kamco/cd/kamcoback/members/service/AuthService.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.members.service; +import com.kamco.cd.kamcoback.members.dto.SignInRequest; import com.kamco.cd.kamcoback.postgres.core.MembersCoreService; import java.util.UUID; import lombok.RequiredArgsConstructor; @@ -32,4 +33,8 @@ public class AuthService { public void loginFail(UUID uuid) { membersCoreService.loginFail(uuid); } + + public boolean existsUsername(SignInRequest request) { + return membersCoreService.existsUsername(request); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java index ca2102f1..e1613003 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java @@ -4,9 +4,11 @@ import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator; 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.Basic; +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.Field; 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.repository.members.MembersRepository; import java.time.ZonedDateTime; @@ -101,6 +103,10 @@ public class MembersCoreService { MemberEntity memberEntity = membersRepository.findById(id).orElseThrow(() -> new MemberNotFoundException()); + if (!memberEntity.getTempPassword().equals(initReq.getTempPassword())) { + throw new PasswordNotFoundException(); + } + String salt = BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim()); // 패스워드 암호화 @@ -157,4 +163,20 @@ public class MembersCoreService { memberEntity.setLoginFailCount(failCnt); membersRepository.save(memberEntity); } + + /** + * 등록, 패스워드가 초기 상태일때 + * + * @param request + * @return + */ + public boolean existsUsername(SignInRequest request) { + MemberEntity memberEntity = membersRepository.findByUserId(request.getUsername()).orElseThrow(MemberNotFoundException::new); + + if (memberEntity.getStatus().equals("INACTIVE") && memberEntity.getTempPassword().equals(request.getPassword())) { + return true; + } + + return false; + } }