사용자 본인의 정보 수정을 하기 전 비밀번호를 입력하여 본인확인 절차를 거치도록 하였다.
[이전] 2021.04.20 - [project/spring] - [JPA] 회원가입과 유효성 체크
사용자가 본인확인을 위해 입력한 비밀번호와 저장된 비밀번호를 비교하기 위해 passwordEncoder 인터페이스 의 메서드를 이용하였다.
MemberService
private final PasswordEncoder passwordEncoder;
@Transactional
public boolean checkMemberPassword(String inputPassword, String memberId) {
return passwordEncoder.matches(inputPassword, loadUserByUsername(memberId).getMemberPw());
}
@Override
public Member loadUserByUsername(String username) throws UsernameNotFoundException {
return memberRepository.findByMemberId(username)
.orElseThrow(()->new UsernameNotFoundException("Not Found by " + username));
}
loadUserByUsername() 은 해당 서비스가 상속받은 UserDetailsService 의 메서드를 오버라이딩한 것으로, 서비스나 컨트롤러 내에서 username으로 Member객체를 조회해야할 때 (DTO가 따로 필요없이 서비스 로직을 위해 이용하거나 DB에 직접적으로 영향을 미칠 때) 주로 사용하였다.
inputPassword는 입력받은 비밀번호이고
memberId는 현재 로그인한 사용자의 아이디이며 해당 아이디로 Member객체를 찾아 저장된 비밀번호를 조회한다.
이 둘을 비교하여 일치하면 true를 일치하지 않으면 false를 반환한다.
MemberApiRespository
@PostMapping("/password/check")
public ResponseEntity<?> checkPassword(Authentication authentication, @RequestBody Map<String, Object> params) {
if(memberService.checkMemberPassword(params.get("password").toString(), authentication.getPrincipal().toString()) == false){
throw new BadRequestException("잘못된 비밀번호 입니다.");
} else {
return ResponseEntity.ok(true);
}
}
Authentication 객체를 이용해 현재 로그인한 사용자의 정보를 받아온다.
RequestBody에는 입력한 비밀번호값만 받으면 됨으로 따로 DTO를 만들지 않고 Map으로 받았다.
>> 비밀번호 불일치인 경우
checkMemberPassword()의 반환값이 false일때(비밀번호가 일치하지 않을 때) 사용자에게 보여줄 메시지를 담아 BadReqeustException을 반환한다.
BadRequestException
@ResponseStatus(value = HttpStatus.CONFLICT)
public class BadRequestException extends RuntimeException {
public BadRequestException(String message) {
super(message);
}
}
>> 비밀번호 일치인 경우
반환값이 true일 때(비밀번호가 일치할 때) true를 반환한다.
원래는 ApiResponse를 만들어 성공여부, 메시지, 에러코드, 반환할 데이터 등을 담아 반환하였으나 성공했을 때 딱히 넘겨줄 데이터가 없어 ResponseEntity에 바로 true를 담아 반환하였다.
+ 쓰다보니 굳이 ApiResponse를 써야하나 의문이 든다. 대부분 성공했을 때 데이터를 담아 ApiResponse를 반환하기 때문에 에러코드나 에러 메시지를 담을 때가 거의 없다. 에러 발생 시 ApiResponse에 에러코드를 넘겨 반환하기보다는 때에 따라 Exception객체를 만들어 반환하고 있다. 또한 성공 시 넘겨줄 데이터가 간단하거나 없을 경우에는 위와 같은 식으로 ResponseEntity Body에 바로 담아 넘겨준다. 각 경우의 쓰임새와 방법에 대해 고민을 해봐야할 것 같다 🤔
먼저 비밀번호로 사용자 인증에 성공하면 기존의 저장된 사용자정보를 보여주었다.
MemberService
@Transactional
public MemberInfoDto findMemberInfoByName(String memberName) {
Member member = loadUserByUsername(memberName);
return new MemberInfoDto(member);
}
직접적으로 화면에 노출되기 때문에 MemberInfoDto로 변환하여 반환하였다.
*API 개발 시 엔티티를 바로 반환하는 것은 매우 좋지 않다
MemberInfoDto
@Getter
@Setter
@NoArgsConstructor
public class MemberInfoDto {
private long memberNo;
private String memberId;
private String memberName;
private String memberPw;
private String memberTell;
private String memberEmail;
@Builder
public MemberInfoDto(Member member) {
this.memberNo = member.getMemberNo();
this.memberName = member.getMemberNm();
this.memberId = member.getMemberId();
this.memberPw = member.getMemberPw();
this.memberTell = member.getMemberTell();
this.memberEmail = member.getMemberEmail();
}
}
Builder를 이용하여 Member에서 MemberInfoDto로 바꿈으로써 코드 반복을 줄이고 재사용성을 높혔다.
(생각보다 Member를 MemberInfoDto로 바꿔 화면에 뿌려줘야할 때가 많았듬)
MemberApiController
@GetMapping("/info/me")
public ResponseEntity<?> memberDetailInfo(Authentication authentication) {
ApiResponse apiResponse = new ApiResponse(true, "로그인한 사용자 상세정보 조회");
apiResponse.putData("memberInfo", memberService.findMemberInfoByName(authentication.getPrincipal().toString()));
return ResponseEntity.ok(apiResponse);
}
마찬가지로 Authentication 객체로 현재 로그인한 사용자의 정보를 받는다.
사용자가 비밀번호를 입력하고 본인인증이 성공하면 위의 api를 호출해 기존에 DB에 저장되어 있던 사용자의 정보를 보여준다.
MemberUpdateRequest
@Getter
@NoArgsConstructor
public class MemberUpdateRequest {
@NotBlank
private long memberNo;
@NotBlank
private String memberId;
@Email
private String memberEmail;
@NotBlank
private String memberTell;
}
사용자가 변경할 수 있는 필드와 사용자를 식별할 수 있는 필드들이 포함되어 있다.
MemberRepository
@Transactional
public void editMemberInfo(MemberUpdateRequest memberUpdateRequest) {
Member member = memberRepository.getOne(memberUpdateRequest.getMemberNo());
member.updateMemberInfo(memberUpdateRequest.getMemberEmail(), memberUpdateRequest.getMemberTell());
}
MemberUpdateRequest에 MemberNo정보가 포함되어 있어 JPA가 제공하는 getOne()메서드로 Member 객체를 조회한다.
* 데이터가 어디서 변경되었는지 찾기 힘들기 때문에 setter를 남발하는 것은 좋지 않다.
게시판 CRUD때와 마찬가지로 setter 대신 도메인에 서비스로직을 구현하였다.
Member
public void updateMemberInfo(String memberEmail, String memberTell) {
this.memberEmail = memberEmail;
this.memberTell = memberTell;
}
엔티티에 작성한 update 로직 (이메일과 전화번호만 바꿀 수 있다고 가정)
MemberApiController
@PutMapping("/edit")
public ResponseEntity<?> editMemberInfo(@RequestBody MemberUpdateRequest memberUpdateRequest) {
ApiResponse apiResponse = new ApiResponse(true, "사용자 정보 수정");
memberService.editMemberInfo(memberUpdateRequest);
return ResponseEntity.ok(apiResponse);
}
정보 수정임으로 PutMapping으로 매핑하였다.
나머지 유효성 검사는 jQuery 처리가 전부..
사용자 정보 수정 끝 ~
[QueryDSL] 동적쿼리로 사용자 조회하기 (0) | 2021.05.18 |
---|---|
[QueryDSL] 카테고리별 게시글 조회 (0) | 2021.04.29 |
[ERROR] 스프링부트 테스트 IllegalStateException (0) | 2021.04.29 |
[JPA] 회원가입시 아이디 중복검사 (0) | 2021.04.20 |
[JPA] 회원가입과 유효성 체크 (0) | 2021.04.20 |
댓글 영역