1. 인메모리 유저 추가하기
- Spring Boot - Spring Security에서 하나의 유저만 추가한다면 프로퍼티 설정을 통해서 추가할 수 있다
spring:
security:
user:
name: user
password: 123!
roles: USER
- 하지만 프로퍼티 파일을 통해서는 오직 한명만 추가할 수 있기 때문에, 여러명을 추가하려면
WebSecuityConfigurerAdapter
의 configure
메소드를 오버라이딩 해야한다
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("user123").roles("USER").and()
.withUser("admin").password("admin123").roles("ADMIN");
}
2. Prefix 미설정으로 인한 로그인 실패
- 하지만 이때 비밀번호를 인코딩하지 않고 평문을 설정한다면,
DelegatingPasswordEncoder
클래스의 내부 클래스인 UnmappedIdPasswordEncoder
의 matches
메소드에 의해 예외가 발생한다.
private class UnmappedIdPasswordEncoder implements PasswordEncoder {
...
public boolean matches(CharSequence rawPassword, String prefixEncodedPassword) {
String id = DelegatingPasswordEncoder.this.extractId(prefixEncodedPassword);
throw new IllegalArgumentException("There is no PasswordEncoder mapped for the id \"" + id + "\"");
}
}
- 이를 해결하기 위해서는 prefix가 있어야한다.
DelagatingPasswordEncoder
클래스는 다양한 해시 알고리즘별 PasswordEncoder
를 제공하는데, 알고리즘에 맞게 인코더를 선택하기 위해 패스워드 앞에 prefix가 있어야한다. DelagatingPasswordEncoder
는 기본적으로 bcrypt를 사용한다
{noop}password123
{bcrypt}$2a$12$0n.nKp3ZY8kmoZMY6jdDi.e6bo.Q8.jPxmvhWl0QHLR6H/qY.a/J.
... 등등 ...
- 일단 아무런 해싱을 안한다면 "{noop}"을 아래처럼 추가할 수 있다
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("{noop}user123").roles("USER").and()
.withUser("admin").password("{noop}admin123").roles("ADMIN");
}
3. PasswordEncoder.upgradeEncoding()
PasswordEncoder
인터페이스는 보안 향상을 위해 다시 인코딩 해야한다면 true
를 반환하는 upgradeEncoding()
메소드를 제공한다. 기본 구현으로는 항상 false
를 반환하지만 InMemoryUserDetailsManger
를 사용한다면, 최초 로그인 성공시 noop에서 bcrypt로 인코더가 변경된다
@Override
protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
UserDetails user) {
boolean upgradeEncoding = this.userDetailsPasswordService != null
&& this.passwordEncoder.upgradeEncoding(user.getPassword());
if (upgradeEncoding) {
String presentedPassword = authentication.getCredentials().toString();
String newPassword = this.passwordEncoder.encode(presentedPassword);
user = this.userDetailsPasswordService.updatePassword(user, newPassword);
}
return super.createSuccessAuthentication(principal, authentication, user);
}