Sprgin Security Username대신 Email 인증 - f-lab-edu/jshop GitHub Wiki
개요
스프링 시큐리티의 UsernamePasswordAuthenticationFilter
를 사용해, 이메일과 패스워드로 인증하는 작업이다.
상세
시큐리티 필터중 UsernamePasswordAuthenticationFilter
는 시큐리티 필터체인 중간쯤에 위치한 필터이며 역할은 사용자의 이름 username
와 비밀번호 password
로 인증을 하는 필터다.
필터는 내부 메서드 attemptAuthentication
에서 유저 이름과, 비밀번호로 인증토큰을 생성하고 인증토큰의 검증을 AuthenticationManager
에게 위임한다. 성공하면 내부 메서드인 successfulAuthentication
이 수행되고, 실패되면 unsuccessfulAuthentication
이 수행된다.
이 과정에서 유저의 이메일과, 비밀번호를 인증토큰으로 전달하도록 구현했다.
AuthenticationManager
의 구현체는 ProviderManager
이며 이번 프로젝트에서는 건들지 않았다.
ProviderManager
에게 인증 토큰이 들어오면 내부적으로 DaoAuthenticationProvider
에게 전달된다.
DaoAuthenticationProvider
은 UserDetailsService
를 주입받으며 UserDetailsService.loadUserByUsername
메서드로 UserDetails
를 가져온다.
그리고 UserDetails.getUsername
, UserDetails.getPassword
를 사용해 인증작업을 수행한다.
내가 구현한 부분은
UserDetailsService
와UserDetails
다.
UserDetailsService.loadUserByUsername
는 인증토큰으로 넘어온 이메일을 사용해 유저를 찾아UserDetails
타입으로 리턴해주는 역할을 한다.// CustomUserDetailService.java @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { User user = userRepository.findByEmail(email); ...
유저 레포지토리에서 이메일을 사용해 유저를 찾고 이를
UserDetails
로 래핑해 리턴한다.
인증 작업에서는 UserDetails.getUsername
, UserDetails.getPassword
가 사용되므로, UserDetails
의 getUsername
메서드의 리턴값을, email
로 설정했다.
// CustomUserDetails.java @Override public String getUsername() { return user.getEmail(); }
후기
처음에는 JWT 강의를 따라하며 username
과 password
로 인증하는 방법에 대해 배우게 되었다.
하지만 유저 엔티티의 username
이 아닌 다른 컬럼(email
) 로 인증을 하려하니 컴포넌트간 동작원리에 대해 이해가 부족해 진행할 수 없었다.
username
컬럼에 이메일을 저장하는 방법으로 간단하게 해결할 수 있었지만, 보다 근본적인 해결책을 원했다.
시큐리티 공식문서를 보며 필터와 컴포넌트간의 동작 원리에 대해 이해하니 원하는 동작을 수행할 수 있었다.
이 경험으로 다시한번 프레임워크와 라이브러리의 차이에 대해 확실하게 알게되었다.
프레임워크의 경우 개발자는 애플리케이션의 제어권이 없다.
스프링 시큐리티또한 정해진 순서대로 필터가 동작하며 개발자는 이 필터에 자신이 원하는 동작을 정의하는것 뿐, 애플리케이션의 제어를 하지 않는다.
이번 경우에도 인증을 위해
UserDetails
타입의getUsername
,getPassword
가 사용되는건 알지만, 개발자가 메서드의 호출을 제어하지는 않는다. 또, 추상화에 대한 큰 장점또한 느꼈다. 위에서 말했듯 개발자는UserDetails.getUsername
을 직접 호출하지 않는다.프레임워크 내부에서
getUsername
을 호출하고, 이를 호출하기 위해 인터페이스인UserDetails
에 의존한다.또한
UserDetailsService
도 마찬가지로 인터페이스에 대한 의존만 하지 프레임워크로부터 구현체를 주입받아 동작하게 된다.프레임워크에 대한 이해와 추상화에 대한 이해가 한층 올라가는 경험이였다.