이 만악의 근원. 내가 이 오류 때문에 하루를 다 태웠다..
구글에 서치해보니 PasswordEncoder를 빈에 등록해야한다, 앞에 아이디를 수동으로 붙여줘야한다.. 말이 많았는데
@Bean
public PasswordEncoder passwordEncoder() {
return new BcryptPasswordEncoder();
}
return MemberDetails.builder()
.sid(member.getSid())
.email(member.getEmail())
.password("{noop}" + passwordEncoder.encode(member.getPassword()))
.nickname(member.getNickname())
.authorities(authorities)
.build();
📍 id가 noop인지 bcrypt인지는 PasswordEncoder의 구현체가 무엇인지에 따라 다르다
패스워드를 입력받는(?) 코드에서는 반드시 패스워드를 인코딩해줘야 한다는데 더이상 인코딩 할 부분은 없는 것 같고
그래서 오류 코드를 더 잘 뜯어봤다..
말 그대로 PasswordEncoder의 id에 null이 들어갔다..
오류 로그를 보면 내가 작성한 클래스 말고도 어떤 클래스의 어느 부분에서 오류가 났는지를 확인할 수 있다.
DelegatingPasswordEncoder class의 함수에서 오류 발생
@Override
public boolean matches(CharSequence rawPassword, String prefixEncodedPassword) {
String id = extractId(prefixEncodedPassword);
throw new IllegalArgumentException("There is no PasswordEncoder mapped for the id \"" + id + "\"");
}
우선 예외 메시지가 왜 터지는지 발견
extractId가 딱 봐도 인코딩된 password의 앞에 붙는 {id} 추출하는 것 같은데 이게 없나보구나 했다 (실제로 DB에도 붙어있지 않았다)
그래도 일단 extractId
도 봐주기로 했다
private String extractId(String prefixEncodedPassword) {
if (prefixEncodedPassword == null) {
return null;
}
// 생략
}
역시나 인코딩된 password의 접두에 붙는 {id}가 없어서 발생하는 오류.
Spring Security 5.0이 되면서 뭐가 많이 바꼈다더니 그 오류가 맞는 듯 했다.
The general format for a password is: {id}encodedPassword
Such that id is an identifier used to look up which PasswordEncoder should be used and encodedPassword is the original encoded password for the selected PasswordEncoder. The id must be at the beginning of the password, start with { and end with }. If the id cannot be found, the id will be null. For example, the following might be a list of passwords encoded using different id. All of the original passwords are "password".
https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released
그리고 왠지 오류가 DelegatingPasswordEncoder에서 발생한게 수상해서 PasswordEncoder의 구현체를 DelegatingPasswordEncoder로 바꿔주었다
WebSecurityConfig
@Bean
public PasswordEncoder passwordEncoder() {
DelegatingPasswordEncoder delegatingPasswordEncoder =
(DelegatingPasswordEncoder) PasswordEncoderFactories.createDelegatingPasswordEncoder();
delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(new BCryptPasswordEncoder());
return delegatingPasswordEncoder;
}
BCryptPasswordEncoder에서 DelegatingPasswordEncoder로 수정했더니 id 'null' 오류가 해결되면서 DB에도 {BCrypt} + 인코딩된 password저장되었다.
여담으로 이 오류 수정 후에도 오류가 많이 발생했다😑
그치만 정말 오류 코드 뜯어보면서 다~ 고쳐서 결국 로그인 구현 성공했다..