모종닷컴

PreAuthorize 우선순위 본문

Programming/Spring

PreAuthorize 우선순위

모종 2022. 8. 2. 23:11
반응형

스프링 시큐리티의 PreAuthorize를 사용하다가 조심해야 할 부분인 것 같아 글로 적어봅니다. Gradle + Kotlin + Spring Boot + Spring Security 조합으로 프로젝트를 구성하였는데 이 구성을 블로그 글에 하나씩 올리자니 너무 내용이 길어지는 것 같아 전부 설명하지 않고 일부분만 코드를 올리도록 하겠습니다.

Gradle Dependency 추가

implementation "org.springframework.boot:spring-boot-starter-security"

Security Configure

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfig : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http.csrf()
            .ignoringAntMatchers("/api/**")
            .ignoringAntMatchers("/admin/**")
            .and().authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/api/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .and()
            .logout()
    }

    override fun configure(auth: AuthenticationManagerBuilder) {
        auth.inMemoryAuthentication()
            .withUser("admin1").password(passwordEncoder().encode("1234")).roles("ADMIN", "ADMIN_READ")
            .and()
            .withUser("admin2").password(passwordEncoder().encode("1234")).roles("ADMIN", "ADMIN_READ", "ADMIN_WRITE")
    }

    @Bean
    fun passwordEncoder() = BCryptPasswordEncoder()
}
  • /admin으로 시작하는 경로에는 ADMIN 권한이 있어야만 접근이 가능하도록 설정합니다.
  • /api로 시작하는 경로는 모두 접근할 수 있도록 설정합니다.
  • 그 외 경로는 모두 로그인이 필요하도록 설정합니다.
  • 인메모리에 admin1 , admin2 유저 생성 비밀번호는 둘 다 1234이고, admin2는 ADMIN_WRITE 권한이 추가적으로 있음.
  • EnableGlobalMethodSecurity 설정으로 PreAuthorize가 동작하도록 설정

테스트 컨트롤러

@RestController
@RequestMapping("/admin")
@PreAuthorize("hasRole('ROLE_ADMIN_WRITE')")
class AdminController {
    @GetMapping("/read")
    fun read(): ResponseEntity<String> {
        return ResponseEntity.ok("admin_read")
    }

    @PreAuthorize("hasRole('ROLE_ADMIN_READ')")
    @GetMapping("/write")
    fun write(): ResponseEntity<String> {
        return ResponseEntity.ok("admin_write")
    }
}
  • PreAuthorize가 클래스 레벨과 메서드 레벨에 붙은 걸 유의 깊게 봐주세요.

 

테스트하자.

브라우저에서 /admin/read 경로로 들어가면 아래와 같이 로그인 화면이 나올텐데 처음에 username = admin1, password = 1234로 로그인해보자

로그인 화면
403 Forbidden

당연히 거절된다. 이로써 클래스 레벨에 PreAuthorize를 붙여도 동작이 된다는 것을 알 수 있다. (요거 모르는 사람이 은근 있다.)

열일하는 시큐리티

 

이번에는 /admin/write 를 요청해보도록 하죠.
머리 : 나 WRITE 권한 없어서 안되는 거 아냐?
웃기게도 /admin/write를 요청하면 정상적으로 동작함을 알 수 있다. 

못 들어오는거 아니였나요?

결론

PreAuthorize의 우선순위는 [메서드 > 클래스] 이다. 개발하면서 클래스 레벨이 우선순위가 높은 줄 알고 만들었던 API가 있는데 권한이 없는 어드민이 접근이 가능해서 정말 깜짝 놀랐다. 클래스 레벨에 PreAuthorize는 조심하도록 하자.

반응형