회원관리 관리 수정
This commit is contained in:
@@ -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 {
|
||||||
@@ -24,9 +27,9 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
|
|||||||
|
|
||||||
// 1. 유저 조회
|
// 1. 유저 조회
|
||||||
MemberEntity member =
|
MemberEntity member =
|
||||||
membersRepository
|
membersRepository
|
||||||
.findByUserId(username)
|
.findByUserId(username)
|
||||||
.orElseThrow(() -> new BadCredentialsException("ID 또는 비밀번호가 일치하지 않습니다."));
|
.orElseThrow(() -> new BadCredentialsException("ID 또는 비밀번호가 일치하지 않습니다."));
|
||||||
|
|
||||||
// 2. jBCrypt + 커스텀 salt 로 저장된 패스워드 비교
|
// 2. jBCrypt + 커스텀 salt 로 저장된 패스워드 비교
|
||||||
if (!BCrypt.checkpw(rawPassword, member.getPassword())) {
|
if (!BCrypt.checkpw(rawPassword, member.getPassword())) {
|
||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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()));
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user