회원관리 관리 수정

This commit is contained in:
2025-12-10 18:30:44 +09:00
parent bdb5ba7011
commit fc2edf7c6d
9 changed files with 68 additions and 72 deletions

View File

@@ -6,9 +6,11 @@ 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.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
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;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@@ -16,6 +18,7 @@ import org.springframework.stereotype.Component;
public class CustomAuthenticationProvider implements AuthenticationProvider { public class CustomAuthenticationProvider implements AuthenticationProvider {
private final MembersRepository membersRepository; private final MembersRepository membersRepository;
private final UserDetailsService userDetailsService;
@Override @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException { public Authentication authenticate(Authentication authentication) throws AuthenticationException {
@@ -36,6 +39,11 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
// 3. 인증 성공 → UserDetails 생성 // 3. 인증 성공 → UserDetails 생성
CustomUserDetails userDetails = new CustomUserDetails(member); CustomUserDetails userDetails = new CustomUserDetails(member);
// 4. 상태값 확인
if (!userDetails.isEnabled()) {
throw new DisabledException("비활성화된 계정입니다.");
}
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
} }

View File

@@ -46,7 +46,7 @@ public class CustomUserDetails implements UserDetails {
@Override @Override
public boolean isEnabled() { public boolean isEnabled() {
return member.getStatus().equalsIgnoreCase("ACTIVE"); return "ACTIVE".equals(member.getStatus());
} }
public MemberEntity getMember() { public MemberEntity getMember() {

View File

@@ -56,6 +56,10 @@ public class AuthController {
@ApiResponse( @ApiResponse(
responseCode = "401", responseCode = "401",
description = "ID 또는 비밀번호 불일치", description = "ID 또는 비밀번호 불일치",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "400",
description = "미사용 상태",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))) content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
}) })
public ApiResponseDto<TokenResponse> signin( public ApiResponseDto<TokenResponse> signin(
@@ -65,6 +69,12 @@ public class AuthController {
@RequestBody @RequestBody
SignInRequest request, SignInRequest request,
HttpServletResponse response) { HttpServletResponse response) {
//
if (authService.existsUsername(request)) {
// return
}
Authentication authentication = Authentication authentication =
authenticationManager.authenticate( authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())); new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));

View File

@@ -49,12 +49,12 @@ public class MembersApiController {
} }
@Operation(summary = "비밀번호 초기화", description = "비밀번호 초기화") @Operation(summary = "사용자 비밀번호 변경", description = "사용자 비밀번호 변경")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse( @ApiResponse(
responseCode = "201", responseCode = "201",
description = "비밀번호 초기화", description = "사용자 비밀번호 변경",
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",

View File

@@ -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<? extends GrantedAuthority> 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;
}
}

View File

@@ -151,8 +151,13 @@ public class MembersDto {
@Setter @Setter
public static class InitReq { public static class InitReq {
@Schema(description = "패스워드", example = "") @Schema(description = "변경 패스워드", example = "")
@Size(max = 255) @Size(max = 255)
@NotBlank
private String password; private String password;
@Schema(description = "초기 패스워드", example = "")
@NotBlank
private String tempPassword;
} }
} }

View File

@@ -35,4 +35,15 @@ public class MemberException {
super(message); super(message);
} }
} }
public static class PasswordNotFoundException extends RuntimeException {
public PasswordNotFoundException() {
super("Password not found");
}
public PasswordNotFoundException(String message) {
super(message);
}
}
} }

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.members.service; package com.kamco.cd.kamcoback.members.service;
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 java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -32,4 +33,8 @@ public class AuthService {
public void loginFail(UUID uuid) { public void loginFail(UUID uuid) {
membersCoreService.loginFail(uuid); membersCoreService.loginFail(uuid);
} }
public boolean existsUsername(SignInRequest request) {
return membersCoreService.existsUsername(request);
}
} }

View File

@@ -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;
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;
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;
@@ -101,6 +103,10 @@ public class MembersCoreService {
MemberEntity memberEntity = MemberEntity memberEntity =
membersRepository.findById(id).orElseThrow(() -> new MemberNotFoundException()); membersRepository.findById(id).orElseThrow(() -> new MemberNotFoundException());
if (!memberEntity.getTempPassword().equals(initReq.getTempPassword())) {
throw new PasswordNotFoundException();
}
String salt = String salt =
BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim()); BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim());
// 패스워드 암호화 // 패스워드 암호화
@@ -157,4 +163,20 @@ public class MembersCoreService {
memberEntity.setLoginFailCount(failCnt); memberEntity.setLoginFailCount(failCnt);
membersRepository.save(memberEntity); 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;
}
} }