[좌충우돌 개발일지 - Spring Security] DelegatingPasswordEncoder

2022. 12. 14. 07:08프로그래머스/TIL

과제로 로그인 계정을 추가하는 미션을 받았고 PasswordEncoder는 NoOpPasswordEncoder를 사용하라고 했다.

이에 대한 힌트로 DelegatingPasswordEncoder를 찾아보라고 했고 이에 대해서 조금 알아보면서 과제를 진행하려고 한다.

https://godekdls.github.io/Spring%20Security/features/#delegatingpasswordencoder

 

Features

스프링 시큐리티 기능을 소개합니다. 공식 문서에 있는 “features” 챕터를 한글로 번역한 문서입니다.

godekdls.github.io

스프링 공식문서를 한글로 번역해주시는 분의 링크이다.

 

요약해보자면

PasswordEncoder라는 인터페이스는 비밀번호를 안전하게 저장할 수 있게 단방향 변환을 수행한다. ( 보통 이를 통해 저장하는 비밀번호는 인증 시점에 사용자가 입력하는 비밀번호랑 비교하는 용도로 쓴다. )

NoOpPasswordEncoder와 같이 구현체들이 많이 있는데 리팩토링, 확장성 및 호환성 보장을 위해서 DelegatingPasswordEncoder를 도입했다고 한다. 이는 비밀번호를 현재 권장하는 저장 방식으로 인코딩하게 보장하고 비밀번호 검증은 최신 형식과 레거시 형식 모두 지원하고 나중에 인코딩을 변경할 수 있는 방법으로 문제를 해결했다.

 

https://godekdls.github.io/Spring%20Security/authentication/#10104-in-memory-authentication

 

Authentication

서블릿 기반 어플리케이션에 적용할 수 있는 스프링 시큐리티 인증을 설명합니다. 공식 문서에 있는 “authentication” 챕터를 한글로 번역한 문서입니다.

godekdls.github.io

또 다른 키워드였던 AuthenticationManagerBuilder에 관한 문서를 찾아서 첨부한다.


구현 코드 살펴보기

    @Bean
    public UserDetailsService users() {
        UserDetails user = User.builder()
                .username("user")
                .password("{noop}user123")
                .roles("USER")
                .build();
        UserDetails admin = User.builder()
                .username("admin")
                .password("{noop}admin123")
                .roles("USER", "ADMIN")
                .build();
        return new InMemoryUserDetailsManager(user, admin);
    }

처음엔 위와 같이 설정을 했는데 {noop} 키워드가 인코딩을 안한다는 의미이고 encoding을 하는 곳이 없는 것을 볼 수 있다. 그래서 아래와 같이 구성했다.

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Bean
    public UserDetailsService users(PasswordEncoder passwordEncoder) {
        UserDetails user = User.builder()
                .username("user")
                .password(passwordEncoder().encode("user123"))
                .roles("USER")
                .build();
        UserDetails admin = User.builder()
                .username("admin")
                .password(passwordEncoder().encode("admin123"))
                .roles("USER", "ADMIN")
                .build();
        return new InMemoryUserDetailsManager(user, admin);
    }

user, admin을 등록하면서 password를 Encoder를 이용해서 encoding하는 모습이다.