-
Spring Filter Security로 인가처리 - Spring Filter Hands On 3Spring Framework/Filter 2023. 10. 6. 00:01
개요
Spring Security Hands On 시리즈에 들어가야 할 내용 같다고 생각하지만.. Spring Security를 활용하면 조금 더 편리하게 인가처리가 가능하기 때문에 소개하고자 합니다.
Spring Security 의존성 추가
implementation("org.springframework.boot:spring-boot-starter-security")
테스트용 Controller 구현
@RestController class AuthorizationTestController { @GetMapping("/admin/admin-path") fun onlyAdmin(@RequestHeader role: String): String{ return "접근 가능" } @GetMapping("/user-path") fun onlyUser(@RequestHeader role: String): String{ return "접근 가능" } }
SecurityConfig 설정
@Configuration @EnableWebSecurity @EnableMethodSecurity class SecurityConfig { @Bean fun filterChain(httpSecurity: HttpSecurity): SecurityFilterChain { httpSecurity .csrf { it.disable() } .authorizeHttpRequests { it .requestMatchers("/admin/**").authenticated() .requestMatchers("/**").permitAll() } .addFilterBefore(AuthorizationFilter(), UsernamePasswordAuthenticationFilter::class.java) return httpSecurity.build() } }
admin이라는 path가 붙으면 인증을 수행하고, 그렇지 않으면 인증을 수행하지 않도록 구성합니다.
그리고 직접 구현할 AuthroizationFilter를 추가해 둡니다.
@EnableMethodSecurity의 경우에 추후에 @PreAuthorize, @PostAuthorize 등의 어노테이션을 활용하기 위해 선언합니다.
AuthorizationFilter 구현
class AuthorizationFilter : OncePerRequestFilter() { override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) { val isFail = runCatching { val role = request.getHeader("role").uppercase() val authorities: List<GrantedAuthority> = listOf(SimpleGrantedAuthority("$ROLE_PREFIX$role")) val authentication: Authentication = UsernamePasswordAuthenticationToken(null, "", authorities) SecurityContextHolder.getContext().authentication = authentication chain.doFilter(request, response) }.isFailure if (isFail) { response.sendError(HttpStatus.UNAUTHORIZED.value(), "현재 권한으로는 접근할 수 없는 uri입니다.") } } companion object{ const val ROLE_PREFIX = "ROLE_" } }
이전에 Filter를 구현했을 때와 동일하게 OncePerRequestFilter를 활용했습니다.
role을 받아오고 GrantedAuthority 객체를 만들어 넘기고 Authentication 객체를 만듭니다.
GrantedAuthority객체는 현재 사용자가 가지고 있는 권한을 의미하며 ROLE_ADMIN, ROLE_USER와 같이 ROLE_* 형태로 사용됩니다.
추후에 GrantedAuthority 객체를 활용하여 인가를 수행할 수 있습니다.
SecurityContextHolder에서 Context를 가져와 해당 인증객체를 저장해 둡니다.
해당 구현은 Thread Local을 활용하기 때문에 추후에 호출되는 스레드들은 인증객체의 정보를 활용할 수 있게 됩니다.
위의 코드를 한 줄로 요약하자면 헤더에서 값을 꺼내와 Role으로 사용자의 인가를 부여하여 인증이 완료된 객체를 생성해 냅니다.
MethodSecurity 방식 활용
@RestController class AuthorizationTestController { @PreAuthorize("hasRole('ROLE_ADMIN')") @GetMapping("/admin/admin-path") fun onlyAdmin(@RequestHeader role: String): String{ return "접근 가능" } @GetMapping("/user-path") fun onlyUser(@RequestHeader role: String): String{ return "접근 가능" } }
@PreAuthorize 메서드를 활용하여 ROLE_ADMIN인 경우에만 onlyAdmin을 호출할 수 있도록 설정할 수 있습니다.
이제 동료 개발자들이 굳이 SecurityConfig의 필터설정을 보지 않더라도 해당 API는 권한이 필요하다는 것을 알 수 있습니다.
또한 ADMIN 이외에 SUPER_ADMIN, 협력사들의 권한들을 다채롭게 부여하여 다양한 인가를 유연하게 수행할 수 있습니다.
치명적인 단점
해당 방법은 Security를 잘 이해하지 못하고 사용했기 때문에 모든 Path에 AuthorizationFilter가 적용됩니다.
Security의 아키텍처를 이해하는 시간을 가지고 다음 방법을 통해 해결할 수 있습니다.
https://junuuu.tistory.com/859
'Spring Framework > Filter' 카테고리의 다른 글
Spring Filter Logging- Spring Filter Hands On 4 (0) 2023.10.15 Spring Filter Header 인가 처리 - Spring Filter Hands On 2 (1) 2023.10.05 Spring Filter란? - Spring Filter Hands On 1 (0) 2023.10.04