Spring프로젝트에서 2가지 방식으로 인증을 해야하는 경우가 있었다.
root path를 구분지어서 /server
로 들어오는 요청은 appkey라는 파라미터를 통해 인증을 진행하고 싶었고,
/api
로 들어오는 요청은 JWT토큰을 통해 사용자 인증을 진행하고 싶었다.
먼저 Spring security가 뭔지 간단히 알아보자.
@Configuration
@EnableWebSecurity
class WebSecurityConfig : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http.authorizeRequests()
.antMatchers("/home").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
}
@Bean
override fun userDetailsService(): UserDetailsService {
val user = User.withUsername("user")
.password("{bcrypt}\$2a\$10\$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG")
.roles("USER")
.build()
return InMemoryUserDetailsManager(user)
}
}
@EnableWebSecurity
어노테이션을 통해서 Spring security에 필요한 설정들을 활성화 할 수 있고, 세부적인 설정들을 구현하려면 WebSecurityConfigurerAdapter
를 상속받아서 각 기능에 맞는 메서드를 구현하면 된다.
configure(HttpSecurity)
메서드를 통해서 path별로 어떤 권한/인증을 적용할지 설정할 수 있다.
UserDetailsService
는 입력받은 인증정보를 기반으로 사용자 정보를 가져오는 역할을 하는 서비스인데, 여기서는 테스트용이기 때문에 메모리에 사용자정보를 미리 만들어놓는 InMemoryUserDetailsManager
를 사용했다.
사실 어려운 부분은 없이 WebSecurityConfigurer
를 두번 정의해주면 된다.
다만 custom filter를 정의하면서 문제가 있었는데, filter를 bean으로 등록했더니 spring에서 자동으로 필터를 등록하면서 문제가 되었었다.
filter를 bean으로 등록하지 말자
@Configuration
@EnableWebSecurity
class WebSecurityConfig {
@Order(1)
@Configuration
class InternalSecurityConfiguration: WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http
.antMatcher("/server")
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.addFilterBefore(serverTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter::class.java)
.authenticationProvider(preAuthProvider())
.authorizeRequests()
.anyRequest().authenticated()
}
}
@Order(2)
@Configuration
class SecurityConfiguration : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http
.requestMatchers { requestMatchers ->
requestMatchers
.antMatchers("/api")
}
.cors()
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.addFilterBefore(jwtTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter::class.java)
.authenticationProvider(jwtAuthProvider())
.authorizeRequests()
.anyRequest().authenticated()
}
}
}