토이프로젝트를 만들면서 서로 다른 테이블의 사용자 권한 인증을 위한 Spring Security 를 적용에 대해 정리한 글이다.
DB 설계시 일반사용자(Member)와 서비스 제공자(Helper)에 필요한 필드가 각각 달라 따로 분리하여 설계했는데 Spring Security 를 적용하고 권한 인증시 문제가 발생하였다.
하나의 스프링 애플리케이션에서 여러개의 UserDetailsService 구현체를 Spring Security 에 등록해줘도 Spring Security 에서는 둘 중 하나만 인증 과정에 참여하고 나머지 하나는 무시된다고 한다.
하여 다음과 같이 해결했다.
@EnableWebSecurity
@RequiredArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE)
public class HelperSecurityConfig extends WebSecurityConfigurerAdapter {
private final HelperUserDetailService helperUserDetailService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.httpBasic()
.and()
.requestMatchers()
.antMatchers("/helpers/**")
.and()
.authorizeRequests()
.antMatchers("/helpers/login", "/helpers/logout", "/", "/helpers/authenticate").permitAll()
.anyRequest().authenticated();
...
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(helperUserDetailService).passwordEncoder(passwordEncoder());
}
}
@EnableWebSecurity
@RequiredArgsConstructor
public class MemberSecurityConfig extends WebSecurityConfigurerAdapter {
private final MemberUserDetailsService memberUserDetailsService;
@Override
public void configure(WebSecurity web) throws Exception {
...
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login", "/logout", "/", "/authenticate").permitAll()
.anyRequest().hasRole("USER");
...
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(memberUserDetailsService).passwordEncoder(passwordEncoder);
}
}
/helpers 로 들어오는 모든 요청에 대해서는 HelperSecurityConfig 처리, 그 외의 모든 요청에 대해서는 MemberSecurityConfig 에서 처리 하기 위해 @Order(Ordered.HIGHEST_PRECEDENCE) 를 통해 작성한 security config 의 우선순위를 정해줬다.