[Spring] 스프링 시큐리티 버전업으로 인해 발생한 에러

이명범·2022년 8월 3일
0

트러블슈팅

목록 보기
2/8
post-thumbnail

문제

문제가 발생한 코드는 다음과 같습니다.

@Override
public boolean join(MemberRequestDto dto) {
    if (existsById(dto.getId())) {
        return false;
    } if (existsByNickname(dto.getNickname())) {
        return false;
    } if (existsByTel(dto.getTel())) {
        return false;
    }

    BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

    Member member = Member.builder()
            .id(dto.getId())
            .password(encoder.encode(dto.getPassword()))
            .name(dto.getName())
            .nickname(dto.getNickname())
            .gender(dto.getBirth())
            .birth(dto.getBirth())
            .tel(dto.getTel())
            .smoke(dto.getSmoke())
            .address(dto.getAddress())
            .build();

    repository.save(member);

    return true;
}

위의 코드는 회원가입 서비스 로직입니다. 적절한 검증을 거친 후 멤버 엔티티를 DB에 저장하는 것을 볼 수 있습니다. 이 때 비밀번호는 BCryptPasswordEncoder를 통해 암호화를 시킨 상태에서 저장을 합니다.

다음은 해당 엔티티가 DB에 저장이 된 모습입니다.

이후 로그인을 시도해보았습니다.

위의 사진과 같이 에러가 발생했습니다. 😢😢😢

원인

스프링 시큐리티 5.0.0 버전 이후부터는 인코딩된 패스워드에 어떤 PasswordEncoder를 사용했는지 접두사를 붙여주어야 합니다!!

이러한 형태에요 → {id}ENCODED_PASSWORD

만약 BCryptPasswordEncoder를 사용하였다면 {bcrypt}ENCODED_PASSWORD ,
NoOpPasswordEncoder를 사용하였다면 {noop}ENCODED_PASSWORD와 같은 형태가 되겠죠.

해결

이를 해결하기 위해서 단순하게 인코딩된 패스워드에 {bcrypt}를 붙여주는 방법도 있겠지만 스프링 시큐리티에서 제공해주는 아주 깔끔한 방법이 있습니다!

바로 PasswordEncoderFactories에요.

이 클래스에는 createDelegatingPasswordEncoder()라는 메서드가 있는데 PasswordEncoder를 생성해줍니다. 그리고 여기서 생성된 인코더를 사용하면 비밀번호를 암호화시킨 후 인코더의 ID를 자동으로 붙여줍니다!

아래 코드는 제가 사용한 방법이에요.

@Override
public boolean join(MemberRequestDto dto) {
    if (existsById(dto.getId())) {
        return false;
    } if (existsByNickname(dto.getNickname())) {
        return false;
    } if (existsByTel(dto.getTel())) {
        return false;
    }
		
    // 이 부분이 수정되었습니다!!
    PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();

    Member member = Member.builder()
            .id(dto.getId())
            .password(encoder.encode(dto.getPassword()))
            .name(dto.getName())
            .nickname(dto.getNickname())
            .gender(dto.getBirth())
            .birth(dto.getBirth())
            .tel(dto.getTel())
            .smoke(dto.getSmoke())
            .address(dto.getAddress())
            .build();

    repository.save(member);

    return true;
}

그리고 결과를 보여드릴게요.

위와 같이 암호화 된 비밀번호 앞에 {bcrypt}라는 인코더 ID값이 들어갔어요!

그리고 로그인도 성공해서 HTTP 헤더의 Authorization에 JWT값이 잘 들어가는 부분도 확인할 수 있었습니다!

profile
백엔드 개발자가 될거야

0개의 댓글