- request levet에서의 인가를 구현할 모델을 제공합니다.
- 특정 prefix의 url에 대한 인가 권한을 요구할 수 있음
- HttpSecurity 객체를 통해 인가 룰을 정의할 수 있음
1. Understanding How Request Authorization Components Work
인가 동작 순서 (AuthorizationFilter)
- SecurityContextHolder에서 인증 정보를 가져오는 Supplier<Authentication> 생성
- Supplier<Authentication>와 HttpServletRequest를 AuthorizationManager에 전달
- authorizeHttpRequests()에 정의된 규칙들과 매칭하여 인가 판정
인가 실패
- AuthorizationDeniedEvent 이벤트 발생
- AccessDeniedException이 던져짐
- ExceptionTranslationFilter가 AccessDeniedException 예외 처리
- AccessDeniedHandler가 예외 처리 담당
인가 성공
- 다음 필터체인으로 진행
AuthorizationFilter Is Last By Default
- 인가는 필터 맨 마지막에 진행됨
- MVC Controller나 View 요청은 authorizeHttpRequests() 인가를 통과해야 접근 허용됨
All Dispatches Are Authorized
- 즉, REQUEST, FORWARD, INCLUDE, ERROR 디스패치 모두 인가 판단 대상임
- 디스패치별 중복 인가를 방지하는 설정 가능
예시) 디스패치별 중복 인가 발생
더보기
- 내부적으로 Thymeleaf 같은 템플릿으로 렌더링하기 위해 FORWARD할 때 인가 발생
- 예외 발생으로 인해 Spring Boot 기본 에러 페이지 응답 시, ERROR로 디스패치되므로 인가 발생
설정) 중복 인가 방지
더보기
http.authorizeHttpRequests((requests) -> requests
.dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
.anyRequest().authenticated()
);
- FORWARD, ERROR 디스패치는 중복 인가를 수행하지 않음
Authentication Lookup is Deferred
- AuthorizationManager는 Supplier<Authentication>를 사용함
- 인가 필요 없다고 판단되면, 인증 객체를 조회하지 않음 (permitAll(): 인증 정보 조회 안함)
- 성능 최적화에 유리
2. Authorizing an Endpoint
특정 엔드포인트에 권한 인가 설정하기
- Spring Security는 authorizeHttpRequests()에 설정한 패턴/츄기 쌍을 순서대로 평가함
- 첫번째 매칭되는 규칙만 적용
코드
더보기
@Bean
public SecurityFilterChain web(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/endpoint").hasAuthority("USER")
.anyRequest().authenticated()
);
return http.build();
}
테스트 코드로 인가 규칙 검증
@WithMockUser로 api 요청에 쓰일 가짜 사용자 정의 및 주입 가능
예시
더보기
@WithMockUser(authorities="USER")
@Test
void endpointWhenUserAuthorityThenAuthorized() {
this.mvc.perform(get("/endpoint"))
.andExpect(status().isOk()); // 접근 허용
}
@WithMockUser
@Test
void endpointWhenNotUserAuthorityThenForbidden() {
this.mvc.perform(get("/endpoint"))
.andExpect(status().isForbidden()); // USER 권한이 없으므로 403
}
@Test
void anyWhenUnauthenticatedThenUnauthorized() {
this.mvc.perform(get("/any"))
.andExpect(status().isUnauthorized()); // 인증 자체가 안 되어 있으므로 401
}
3. Matching Requests
- 요청을 매칭하여 인가를 적용하는 다양한 방법을 지원함
매칭 방식 | 특징 |
Matching Using Ant |
기본 매칭 방식
와일드카드 지원 (*, **) 경로 변수 활용 가능 |
Matching Using Regular Expressions |
정규식을 사용하여 경로를 정밀하게 매칭 가능
복잡한 규칙 표현에 적합 |
Matching By Http Method |
HTTP 메서드 별로 인가 규칙 적용 가능 (GET, POST 등)
|
Matching By Dispatcher Type |
서블릿 디스패치 종류별로 인가 처리 설정 가능 (FORWARD, ERROR 등)
|
Matching by Servlet Path |
여러 DispatcherServlet이 있는 경우, 서블릿 prefix에 따라 경로 매칭 가능
|
Using a Custom Matcher |
RequestMatcher 구현 또는 람다 사용
요청 속성 기반으로 유연한 매칭 가능 |
예시) ant
더보기
와일드 카드
.requestMatchers("/resource/**").hasAuthority("USER")
경로 변수
.requestMatchers("/resource/{name}")
.access(new WebExpressionAuthorizationManager("#name == authentication.name"))
예시) 정규식
더보기
.requestMatchers(RegexRequestMatcher.regexMatcher("/resource/[A-Za-z0-9]+"))
.hasAuthority("USER")
예시) HTTP 메서드
더보기
.requestMatchers(HttpMethod.GET).hasAuthority("read")
.requestMatchers(HttpMethod.POST).hasAuthority("write")
예시) DispatcherType
더보기
.dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR)
.permitAll()
예시) Servlet Path
더보기
PathPatternRequestMatcher.Builder mvc = withDefaults().basePath("/spring-mvc");
.requestMatchers(mvc.matcher("/admin/**")).hasAuthority("admin")
예시) custom matcher
더보기
request parameter
RequestMatcher printview = (request) -> request.getParameter("print") != null;
.requestMatchers(printview).hasAuthority("print")
- 쿼리 파라미터 존재 여부에 따라 인가 체크
4. Authorizing Requests
Authorization DSL
DSL 메서드 | 설명 |
permitAll() |
모든 사용자 허용.
- 인증 정보조차 조회하지 않음. - 퍼블릭 엔드포인트 처리에 사용 |
denyAll() |
무조건 접근 거부
- 인증 정보도 조회 안 함 - 보안상 기본값이나 fallback 용도로 사용 |
hasAuthority("X") |
인증 객체에 GrantedAuthority("X")가 있어야 접근 가능
|
hasRole("X") |
hasAuthority("ROLE_X")의 축약형
- 내부적으로 ROLE_ prefix 자동 추가 |
hasAnyAuthority("A", "B") |
주어진 권한 중 하나라도 있으면 접근 허용
|
hasAnyRole("A", "B") |
각각 ROLE_A, ROLE_B로 변환 후 검사
|
access(...) |
커스텀 AuthorizationManager 로직 적용
복합 조건 가능 (allOf, anyOf 등) |
예제) 복합 인가
더보기
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.dispatcherTypeMatchers(FORWARD, ERROR).permitAll()
.requestMatchers("/static/**", "/signup", "/about").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/db/**").access(allOf(hasAuthority("db"), hasRole("ADMIN")))
.anyRequest().denyAll()
);
return http.build();
}
5. Expressing Authorization with SpEL
주요 SpEL 메서드
표현식 | 설명 |
permitAll |
누구나 접근 가능. (인증 정보 조회도 안 함)
|
denyAll |
무조건 거부. (인증 정보 조회도 안 함)
|
hasAuthority('X') |
Authentication 객체에 GrantedAuthority("X") 권한이 있어야 접근 가능
|
hasRole('X') |
hasAuthority('ROLE_X')와 동일. ROLE_ prefix 자동 추가됨
|
hasAnyAuthority(...) |
여러 권한 중 하나라도 만족하면 접근 허용
|
hasAnyRole(...) |
각각 ROLE_이 붙은 권한 중 하나라도 만족하면 허용
|
hasPermission(...) |
PermissionEvaluator를 활용한 도메인 객체 수준 인가
|
SpEL 표현식에서 사용 가능한 주요 필드
필드명 | 설명 |
authentication |
현재 인증된 사용자에 대한 Authentication 객체
|
principal |
인증된 사용자의 principal 정보 (getPrincipal())
|
#변수명 |
경로 변수.
예: /resource/{name}에서 #name으로 참조 가능 |
6. Migrating from authorizeRequests
7. Security Matchers
항목 | securityMatcher() |
requestMatchers()
|
역할 | 보안 설정이 어떤 요청에 적용될지 결정 |
인가 규칙을 어떤 요청에 적용할지 결정
|
필터 체인 분기용 | ✅ (다중 필터 체인 구성 시 사용됨) |
❌ (필터 체인 내에서 인가 제어에만 사용됨)
|
위치 | http.securityMatcher(...) |
authorizeHttpRequests().requestMatchers(...) 내부에서 사용
|
예시 | /api/** 요청에만 해당 보안 설정을 적용 |
/api/admin/** 요청은 ROLE_ADMIN만 접근 가능
|
예시
더보기
http
.securityMatcher("/api/**") // 보안 필터체인 적용 범위: /api/** 요청만
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/user/**").hasRole("USER") // USER 역할 필요
.requestMatchers("/api/admin/**").hasRole("ADMIN") // ADMIN 역할 필요
.anyRequest().authenticated() // 그 외는 인증만 필요
)
출처
'Spring > Spring Security' 카테고리의 다른 글
[Spring Security] 6-2. OAuth2 Login: Core Configuration (1) | 2025.07.15 |
---|---|
[Spring Security] 6-1. OAuth2 (0) | 2025.07.13 |
[Spring Security] 4-1. Authorization: Architecture (0) | 2025.07.03 |
[Spring Security] 5-4. 보안: HttpFirewall (0) | 2023.10.14 |
[Spring Security] 5-3. 보안: HTTP Requests (0) | 2023.10.14 |