지난 포스팅에 이어, 이번 포스팅에서는 11)
의 내용을 정리한다.
👉 목차는 다음과 같다.
1) 인증 API - 프로젝트 구성 및 의존성 추가
2) 인증 API - 사용자 정의 보안 기능 구현
3) 인증 API - Form Login 인증
4) 인증 API - Form Login 인증 필터 : UsernamePasswordAuthenticationFilter
5) 인증 API - Logout 처리, LogoutFilter
6) 인증 API - Remember Me 인증
7) 인증 API - Remember Me 인증 필터 : RememberMeAuthenticationFilter
8) 인증 API - 익명사용자 인증 필터 : AnonymousAuthenticationFilter
9) 인증 API - 동시 세션 제어, 세션 고정 보호, 세션 정책
10) 인증 API - 세션 제어 필터 : SessionManagementFilter, ConcurrentSessionFilter
11) 인가 API - 권한 설정 및 표현식
12) 인증/인가 API - 예외 처리 및 요청 캐시 필터 : ExceptionTranslationFilter, RequestCacheAwareFilter
13) Form 인증 - 사이트 간 요청 위조 : CSRF, CsrfFilter
바로 하나씩 확인해보자.
이전 내용까지는 주로 인증 API와 관련된 내용을 학습했다.
이번 내용에서는 인가 API는 어떻게 설정하고, 어떻게 동작하는지 알아보자.
(권한 설정과 표현식을 통해서 인가 처리)
✔️ 권한 설정
http.antMatchers("/users/**").hasRole("USER")
@PreAuthorize("hasRole('USER')") public void user() { System.out.println("user"); }
이번 내용에서는 [선언적 방식 - URL 방식] 으로 권한을 설정하는 내용에 대해서 알아보고,
Method 방식과, 동적 방식은 이후 실전 프로젝트 인가 편에서 살펴보자.
URL 방식
configure(HttpSecurity http)
메서드 안에서 설정하면 된다.http.antMatcher("경로")
: 먼저, antMatcher 를 사용해서 특정 경로를 지정할 수 있다. 그러면 현재 사용자의 요청이 해당 경로로 요청될 때만 설정 클래스에 작성한 보안 기능이 작동하게 된다. 만약 해당 경로가 아닌, 다른 경로로 요청하게 되면, 설정 클래스의 보안 기능은 작동하지 않는다. 따라서, 특정한 자원 경로로 제한해서 인증과 인가 처리를 하고자 할때, antMatcher("경로") 로 적용해주면 된다. 참고로 만약 위 예시에서 antMatcher("경로")를 생략하게 되면, 특정한 자원 경로가 아닌, 모든 요청 경로에 대해서 보안 검사를 진행하게 된다.authorizeRequests()
: 요청에 대한 인가 설정을 시작한다. chaining 형태로 설정할 수 있다.anyMatchers("경로1", "경로2", ..)
: anyMatchers 안에는 여러개의 경로를 작성할 수 있다. 그러면 클라이언트의 request에 담긴 요청 경로와 작성된 경로들을 매칭하고, 동일한 경로 정보가 있거나 포함 관계에 있으면, 그 뒤에 작성한 권한 정보(ex. .permitAll(), .hasRole(..), ..)를 통해서 인가 심사를 한다. 참고로 만약 매칭되지 않으면, 그 다음 anyMatchers(..) 로 계속적으로 이동하여 인가 처리와 관련된 심사를 진행한다. 따라서 작성된 모든 인가 심사를 통과해야 자원에 접근된다.anyRequest().authenticated()
: 특정한 자원 경로에 대한 권한 정보를 제외하고, 그 밖의 모든 요청에 대해서는 인증을 받아야 접근이 가능하다는 의미이다.
✔️ 표현식
antMatchers("경로1", "경로2").permitAll()
anonymous()
표현식에 설정된 자원에 접근할 수 없다. (오로지 익명 사용자만 접근 가능하다.)anonymous()
는 ROLE_ANONYMOUS 권한을 가진 사용자만 접근할 수 있다. 인증된 ROLE_USER 권한을 가진 사용자는 접근할 수 없다. 그러므로, 인증된 사용자나 익명 사용자가 모두 접근 가능해야 하는 경우 permitAll()
을 사용해야 한다.hasRole(String)
작성시, ROLE_USER
라 할때, ROLE_
prefix는 붙이지 않아야 한다. 붙이면 오류가 발생한다.antMatchers("/users/**").hasRole("USER")
hasAuthority(String)
작성시, ROLE_USER
라 할때, ROLE_
prefix를 붙여야 한다.antMatchers("/goods/**").hasAuthority("ROLE_USER")
👉 이제 사용자를 생성하고, 각 사용자에게 권한을 부여하자. 그리고 인가 API를 통해서 자원과 권한 정보를 설정하고 정상적으로 인가 처리가 동작하는지 테스트해보자.
/user
경로는 USER 권한을 가진 사용자만 접근 가능하고,/admin/pay
경로는 ADMIN 권한을 가진 사용자만 접근가능하다. 그리고/admin/**
하위 모든 경로는 ADMIN 권한 또는 SYS 권한을 가진 사용자만 접근이 가능하고,anyRequest().authenticated()
에 의해, 인증된 사용자가 아니므로 로그인 페이지로 이동한다./user
경로로 접근해보자./user
경로에 접근하기 위해서는 USER 권한이 필요하다. 해당 경로로 요청한 user 계정은 USER 권한을 가지고 있으므로 정상적으로 접근되는 것을 확인할 수 있다./admin
으로 접근해보자./admin
경로를 요청해보자./admin
경로에 접근하기 위해서는 ADMIN 또는 SYS 권한이 있어야 한다. sys 계정은 SYS 권한을 가지고 있으므로 접근 가능하다./admin/pay
경로로 접근해보자./admin/pay
경로에 접근하기 위해서는 ADMIN 권한이 있어야 한다. sys 계정은 SYS 권한을 가지고 있으므로 접근이 안되는 것을 확인할 수 있다./user
경로에 접근해도, USER 권한이 아니므로 접근할 수 없다.auth.inMemoryAuthentication().withUser("admin").password("{noop}1111").roles("ADMIN", "SYS", "USER");
.antMatchers("/admin/**").access("hasRole('ADMIN') or hasRole('SYS')")
와 .antMatchers("/admin/pay").hasRole("ADMIN")
의 위치를 바꾸게 된다면, SYS 권한을 가진 sys 계정이 /admin/pay
경로에 접근 가능하게 된다.강의를 듣고 정리한 글입니다. 코드와 그림 등의 출처는 정수원 강사님께 있습니다.