[내일배움캠프] Spring 일정관리 앱 Develop Step5-6.

김재진·2026년 1월 9일

내일배움캠프

목록 보기
35/70

1. Validation을 활용한 예외처리와 비밀번호 암호화

  • Validation과 @RestControllerAdvice 를 사용한 예외처리
  • PasswordEncoder를 이용한 비밀번호 암호화

2. github 주소

3. Validation과 @RestControllerAdvice 를 사용한 예외처리

  • Validation 사용
@Getter
public class UserSignupRequest {

    @NotBlank @Size(max = 4) // 필수 입력값, 4자 이하
    private String username;
    @NotBlank @Email // 필수 입력값, 이메일 형태
    private String email;
    @NotBlank @Size(min = 8, max = 20) // 필수 입력값, 8-20자 
    private String password;
}
---Controller---
@PostMapping("/signup")
    public ResponseEntity<UserSignupResponse> signupUser(
           @Valid @RequestBody UserSignupRequest request // 유효성 검증을 위한 @Valid 어노테이션 사용
    ){
        return ResponseEntity.status(HttpStatus.CREATED).body(userService.save(request));
    }
  • @RestControllerAdvice을 이용해 IllegalStateException을 한번에 처리
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(IllegalStateException.class) 
    public ResponseEntity<String> handleIllegalStateException(IllegalStateException e) {
        return ResponseEntity
                .status(HttpStatus.BAD_REQUEST)
                .body("요청 오류: " + e.getMessage());
    }
}

  • 사진과 같이 오류메시지 전송

4. 비밀번호 암호화

  • PasswordEncoder를 이용한 비밀번호 암호화
@Component
public class PasswordEncoder {

    public String encode(String rawPassword) {
        return BCrypt.withDefaults().hashToString(BCrypt.MIN_COST, rawPassword.toCharArray());
    }

    public boolean matches(String rawPassword, String encodedPassword) {
        BCrypt.Result result = BCrypt.verifyer().verify(rawPassword.toCharArray(), encodedPassword);
        return result.verified;
    }
}
  • UserService
private final PasswordEncoder passwordEncoder; // passwordEncoder 생성

    @Transactional
    public UserSignupResponse save(UserSignupRequest request) {

        // 비밀번호 암호화 
        String encodedPW = passwordEncoder.encode(request.getPassword());

        User user = new User(
                request.getUsername(),
                request.getEmail(),
                encodedPW // 암호화된 비밀번호로 사용
        );
        User savedUser = userRepository.save(user);
        return new UserSignupResponse(
                savedUser.getId(),
                savedUser.getUsername(),
                savedUser.getEmail(),
                savedUser.getCreatedAt(),
                savedUser.getModifiedAt()
        );
    }
    ...
    // 로그인 메서드에서 암호화된 비밀번호 확인
    @Transactional(readOnly = true)
    public SessionUser login(@Valid UserLoginRequest request) {
        User user = userRepository.findByEmail(request.getEmail()).orElseThrow(
                () -> new IllegalStateException("없는 유저입니다.")
        );
        // 비밀번호 확인 
        if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
            throw new IllegalStateException("비밀번호가 틀립니다.");
        }
        return new SessionUser(
                user.getId(),
                user.getUsername(),
                user.getEmail()
        );
    }

5. 트러블 슈팅

  1. 암호화된 비밀번호를 확인하는 과정에서 맞는 비밀번호를 적어도 예외처리 메시지("비밀번호가 틀립니다.")가 전송
  2. PasswordEncoder의 matches 메서드를 확인해보니 rawPassword, encodedPassword 순서로 작성하도록 만들어져 있음
  3. 작성한 코드를 살펴보니 encodedPassword, rawPassword 순서로 작성되어 있어 순서를 바꾸니 정상적으로 작동
// before 
if (!passwordEncoder.matches(user.getPassword(), request.getPassword())) {
            throw new IllegalStateException("비밀번호가 틀립니다.");
        }
// user.getPassword() = encodedPassword, request.getPassword() = rawPassword
// after
if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
            throw new IllegalStateException("비밀번호가 틀립니다.");
        }
profile
개발공부 처음해보는 사람

0개의 댓글