일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 백준 알고리즘
- resilience4j
- smart cast
- jsp
- c#
- K6
- gradle
- 자바 프로젝트
- SQL
- 초대장
- 자바
- 티스토리
- 학점
- 알고리즘
- 프로젝트
- 운영체제
- hyperledger
- spring
- 문법 정리
- JVM
- auto configure
- MongoDB
- oracle
- 오라클
- 파이썬
- 리눅스
- dynamic query
- 오라클 디비
- 유사코드
- 파이썬 소스
Archives
- Today
- Total
모종닷컴
PreAuthorize 우선순위 본문
반응형
스프링 시큐리티의 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로 로그인해보자
당연히 거절된다. 이로써 클래스 레벨에 PreAuthorize를 붙여도 동작이 된다는 것을 알 수 있다. (요거 모르는 사람이 은근 있다.)
이번에는 /admin/write 를 요청해보도록 하죠.
머리 : 나 WRITE 권한 없어서 안되는 거 아냐?
웃기게도 /admin/write를 요청하면 정상적으로 동작함을 알 수 있다.
결론
PreAuthorize의 우선순위는 [메서드 > 클래스] 이다. 개발하면서 클래스 레벨이 우선순위가 높은 줄 알고 만들었던 API가 있는데 권한이 없는 어드민이 접근이 가능해서 정말 깜짝 놀랐다. 클래스 레벨에 PreAuthorize는 조심하도록 하자.
반응형
'Programming > Spring' 카테고리의 다른 글
Mock Layer (0) | 2022.08.17 |
---|---|
Quartz Job Scheduling 1편 - 소개 및 간단한 예제 (0) | 2022.08.14 |
Spring AOP vs AspectJ (0) | 2022.07.27 |
스프링 프록시 못된 녀석 - 2편 (프록시 생성 방식) (0) | 2022.07.17 |
스프링 프록시 못된 녀석 (with 코틀린, all-open) (0) | 2022.07.16 |