Spring Security Architecture
업데이트: Link
Spring 보안 아키텍처
이 가이드는 Spring Security에 대한 입문서로, 프레임워크의 설계와 기본 구성 요소에 대한 인사이트를 제공합니다. 애플리케이션 보안의 가장 기본적인 내용만 다룹니다. 하지만 이를 통해 Spring Security를 사용하는 개발자들이 겪는 혼란을 조금이나마 해소할 수 있습니다. 이를 위해 필터를 사용하고 더 일반적으로 메서드 주석을 사용하여 웹 애플리케이션에서 보안이 적용되는 방식을 살펴봅니다. 보안 애플리케이션이 어떻게 작동하는지, 어떻게 사용자 정의할 수 있는지, 또는 애플리케이션 보안에 대해 생각하는 방법을 배워야 하는 경우 이 가이드를 사용하세요.
이 가이드는 가장 기본적인 문제 이상의 문제를 해결하기 위한 매뉴얼이나 레시피는 아니지만(이러한 문제에 대한 다른 출처가 있음), 초보자와 전문가 모두에게 유용할 수 있습니다. 또한 보안 애플리케이션에 대한 몇 가지 기본 동작을 제공하고 전체 아키텍처에 어떻게 부합하는지 이해하는 데 유용할 수 있으므로 Spring Boot를 자주 참조합니다.
Note
All of the principles apply equally well to applications that do not use Spring Boot.
인증 및 액세스 제어
애플리케이션 보안은 인증(사용자가 누구인가?)과 권한 부여(무엇을 할 수 있는가?)라는 다소 독립적인 두 가지 문제로 요약됩니다. 때때로 사람들은 “권한 부여” 대신 “접근 제어”라고 말해서 혼동할 수 있지만, “권한 부여”는 다른 곳에서 과부하가 걸리기 때문에 그렇게 생각하는 것이 도움이 될 수 있습니다. Spring Security는 인증과 권한 부여를 분리하도록 설계된 아키텍처를 가지고 있으며, 두 가지 모두에 대한 전략과 확장 지점을 가지고 있습니다.
인증
인증을 위한 주요 전략 인터페이스는 AuthenticationManager
이며, 메서드는 하나뿐입니다:
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
AuthenticationManager
는 authenticate()
메서드에서 다음 세 가지 중 하나를 수행할 수 있습니다:
-
입력이 유효한 주체를 나타내는지 확인할 수 있는 경우
Authentication
(일반적으로authenticated=true
과 함께)을 반환합니다. -
입력이 유효하지 않은 주체를 나타내는 것으로 판단되면
AuthenticationException
을 던집니다. -
결정할 수 없으면
null
을 반환합니다.
AuthenticationException
은 런타임 예외입니다. 일반적으로 애플리케이션의 스타일이나 목적에 따라 애플리케이션에서 일반적인 방식으로 처리합니다. 즉, 사용자 코드는 일반적으로 이를 포착하여 처리할 것으로 예상되지 않습니다. 예를 들어, 웹 UI는 인증에 실패했다는 페이지를 렌더링할 수 있으며, 백엔드 HTTP 서비스는 컨텍스트에 따라 WWW-Authenticate
헤더를 포함하거나 포함하지 않고 401 응답을 보낼 수 있습니다.
AuthenticationManager
의 가장 일반적으로 사용되는 구현은 AuthenticationProvider
인스턴스 체인에 위임하는 ProviderManager
입니다. AuthenticationProvider
는 AuthenticationManager
와 비슷하지만 호출자가 주어진 Authentication
유형을 지원하는지 여부를 쿼리할 수 있는 추가 메서드가 있습니다:
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
boolean supports(Class<?> authentication);
}
supports()
메서드의 Class<?>
인수는 실제로는 Class<? extends Authentication>
입니다(authenticate()
메서드로 전달된 것을 지원하는지 여부만 묻습니다). ProviderManager
는 AuthenticationProvider
의 체인에 위임하여 동일한 애플리케이션에서 여러 가지 인증 메커니즘을 지원할 수 있습니다. ProviderManager
가 특정 Authentication
인스턴스 유형을 인식하지 못하면 건너뜁니다.
ProviderManager
에는 선택적 부모가 있으며, 모든 프로바이더가 null
을 반환하는 경우 참조할 수 있습니다. 부모를 사용할 수 없는 경우, null
Authentication
은 AuthenticationException
을 발생시킵니다.
애플리케이션에 보호된 리소스의 논리적 그룹(예: /api/**
와 같은 경로 패턴과 일치하는 모든 웹 리소스)이 있는 경우가 있으며, 각 그룹에는 고유한 전용 AuthenticationManager
가 있을 수 있습니다. 종종 이들 각각은 ProviderManager
이며, 이들은 하나의 부모를 공유합니다. 그러면 부모는 일종의 “글로벌” 리소스로서 모든 공급자에 대한 폴백 역할을 합니다.
Figure 1. An AuthenticationManager
hierarchy using ProviderManager
Customizing Authentication Managers
스프링 시큐리티는 애플리케이션에서 일반적인 인증 관리자 기능을 빠르게 설정할 수 있도록 몇 가지 구성 도우미를 제공합니다. 가장 일반적으로 사용되는 헬퍼는 인메모리, JDBC 또는 LDAP 사용자 세부 정보를 설정하거나 사용자 정의 UserDetailsService
를 추가하는 데 유용한 AuthenticationManagerBuilder
입니다. 다음 예제는 글로벌(부모) AuthenticationManager
를 구성하는 애플리케이션을 보여줍니다:
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
... // web stuff here
@Autowired
public void initialize(AuthenticationManagerBuilder builder, DataSource dataSource) {
builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
.password("secret").roles("USER");
}
}
이 예제는 웹 애플리케이션에 관한 것이지만, AuthenticationManagerBuilder
의 사용법은 더 광범위하게 적용할 수 있습니다(웹 애플리케이션 보안 구현 방법에 대한 자세한 내용은 웹 보안을 참조하세요). AuthenticationManagerBuilder
는 @Bean
의 메서드에 @Autowired
되어 있으며, 이것이 글로벌(부모) AuthenticationManager
를 빌드하게 한다는 점에 유의하십시오. 반대로 다음 예제를 살펴보겠습니다:
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
... // web stuff here
@Override
public void configure(AuthenticationManagerBuilder builder) {
builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
.password("secret").roles("USER");
}
}
컨피규레이터에서 메서드의 @Override
를 사용했다면, AuthenticationManagerBuilder
는 전역의 자식이 되는 “로컬” AuthenticationManager
를 빌드하는 데만 사용되었을 것입니다. Spring Boot 애플리케이션에서는 글로벌 빈을 다른 빈에 @Autowired
할 수 있지만, 로컬 빈은 명시적으로 노출하지 않는 한 그렇게 할 수 없습니다.
AuthenticationManager
유형의 자체 빈을 제공하여 선점하지 않는 한 Spring Boot는 기본 글로벌 AuthenticationManager
(사용자 한 명만 있음)를 제공합니다. 기본값은 그 자체로 충분히 안전하므로 사용자 정의 글로벌 AuthenticationManager
가 적극적으로 필요하지 않는 한 크게 걱정할 필요가 없습니다. AuthenticationManager
를 빌드하는 구성을 수행하는 경우 보호하려는 리소스에 로컬로 수행하면 글로벌 기본값에 대해 걱정하지 않아도 됩니다.
권한 부여 또는 액세스 제어
인증이 성공하면 권한 부여로 넘어갈 수 있으며, 여기서 핵심 전략은 AccessDecisionManager
입니다. 프레임워크에서 제공하는 세 가지 구현이 있으며, 세 가지 모두 ProviderManager
가 AuthenticationProviders
를 위임하는 것과 비슷하게 AccessDecisionVoter
인스턴스 체인에 위임합니다.
AccessDecisionVoter
는 (주체를 나타내는) Authentication
과 ConfigAttributes
로 장식된 보안 Object
를 고려합니다:
boolean supports(ConfigAttribute attribute);
boolean supports(Class<?> clazz);
int vote(
Authentication authentication,
S object,
Collection<ConfigAttribute> attributes
);
Object
는 AccessDecisionManager
와 AccessDecisionVoter
의 시그니처에서 완전히 일반적입니다. 이는 사용자가 접근하고자 하는 모든 것을 나타냅니다(웹 리소스나 Java 클래스의 메서드가 가장 일반적인 두 가지 경우입니다). ConfigAttributes
역시 상당히 일반적인 것으로, 접근에 필요한 권한 수준을 결정하는 몇 가지 메타데이터로 보안 Object
를 장식하는 것을 나타냅니다. ConfigAttributes
는 인터페이스입니다. 메서드는 하나뿐이며(매우 일반적이고 String
을 반환함), 이 문자열은 리소스 소유자의 의도를 어떤 식으로든 인코딩하여 누가 리소스에 액세스할 수 있는지에 대한 규칙을 표현합니다. 일반적인 ConfigAttribute
는 사용자 역할의 이름(예: ROLE_ADMIN
또는 ROLE_AUDIT
)이며, 종종 특수 형식(예: ROLE_
접두사)을 갖거나 평가해야 하는 표현식을 나타내기도 합니다.
대부분의 사람들은 기본 ‘AccessDecisionManager’인 AffirmativeBased
를 사용합니다(유권자가 긍정적으로 응답하면 액세스 권한이 부여됨). 모든 사용자 지정은 새로운 유권자를 추가하거나 기존 유권자의 작동 방식을 수정하여 유권자에서 발생하는 경향이 있습니다.
스프링 표현식 언어(SpEL) 표현식인 ConfigAttributes
를 사용하는 것이 매우 일반적입니다(예: isFullyAuthenticated() && hasRole('user')
). 이는 표현식을 처리하고 해당 표현식에 대한 컨텍스트를 생성할 수 있는 AccessDecisionVoter
에 의해 지원됩니다. 처리할 수 있는 표현식의 범위를 확장하려면 SecurityExpressionRoot
의 사용자 정의 구현이 필요하며 때로는 SecurityExpressionHandler
도 필요합니다.
Web Security
웹 계층(UI 및 HTTP 백엔드용)의 Spring Security는 서블릿 Filters
를 기반으로 하므로, 먼저 Filters
의 역할을 전반적으로 살펴보는 것이 도움이 됩니다. 다음 그림은 단일 HTTP 요청에 대한 핸들러의 일반적인 계층화를 보여줍니다.
클라이언트가 애플리케이션에 요청을 보내면 컨테이너는 요청 URI의 경로에 따라 어떤 필터와 어떤 서블릿을 적용할지 결정합니다. 최대 하나의 서블릿이 하나의 요청을 처리할 수 있지만 필터는 하나의 체인을 형성하므로 순서가 정해집니다. 실제로 필터는 요청 자체를 처리하려는 경우 나머지 체인을 거부할 수 있습니다. 또한 필터는 다운스트림 필터와 서블릿에서 사용되는 요청이나 응답을 수정할 수도 있습니다. 필터 체인의 순서는 매우 중요하며, Spring Boot는 두 가지 메커니즘을 통해 이를 관리합니다. Filter
유형의 @Bean
은 @Order
를 갖거나 Ordered
를 구현할 수 있으며, 그 자체로 API의 일부로 순서를 갖는 FilterRegistrationBean
의 일부가 될 수 있습니다. 일부 기성 필터는 자체 상수를 정의하여 서로에 대해 어떤 순서를 원하는지 알 수 있습니다(예를 들어, Spring Session의 SessionRepositoryFilter
는 DEFAULT_ORDER
가 Integer.MIN_VALUE + 50
으로, 체인에서 앞쪽에 있는 것을 좋아하지만 그 앞에 오는 다른 필터를 배제하지 않습니다).
스프링 시큐리티는 체인에 하나의 Filter
로 설치되며, 그 구체적인 유형은 곧 다루게 될 FilterChainProxy
입니다. 스프링 부트 애플리케이션에서 보안 필터는 ApplicationContext
의 @Bean
이며, 모든 요청에 적용되도록 기본적으로 설치되어 있습니다. 보안 필터는 SecurityProperties.DEFAULT_FILTER_ORDER
에 의해 정의된 위치에 설치되며, 이는 다시 FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER
(Spring Boot 애플리케이션에서 필터가 요청을 래핑하여 동작을 수정할 경우 예상되는 최대 순서)에 의해 고정됩니다. 하지만 이보다 더 많은 것이 있습니다: 컨테이너의 관점에서 보면 Spring Security는 단일 필터이지만, 그 내부에는 각각 특별한 역할을 하는 추가 필터가 있습니다. 다음 이미지는 이러한 관계를 보여줍니다:
Figure 2.Spring Security는 하나의 물리적 Filter
이지만 내부 필터 체인에 처리를 위임합니다.
사실, 보안 필터에는 한 단계 더 간접적인 계층이 있습니다: 일반적으로 컨테이너에 DelegatingFilterProxy
로 설치되며, 이는 Spring @Bean
일 필요는 없습니다. 프록시는 항상 @Bean
인 FilterChainProxy
에 위임하며, 일반적으로 springSecurityFilterChain
이라는 고정된 이름을 갖습니다. 내부적으로 필터 체인(또는 체인)으로 배열된 모든 보안 로직이 포함된 것은 FilterChainProxy
입니다. 모든 필터는 동일한 API를 가지고 있으며(모두 서블릿 사양의 Filter
인터페이스를 구현함), 나머지 체인에 대해 거부권을 행사할 수 있습니다.
동일한 최상위 레벨인 FilterChainProxy
에서 Spring Security가 관리하는 필터 체인은 여러 개가 있을 수 있으며 모두 컨테이너에 알려지지 않습니다. Spring Security 필터에는 필터 체인 목록이 포함되어 있으며 일치하는 첫 번째 체인에 요청을 디스패치합니다. 다음 그림은 요청 경로 일치에 따라 발생하는 디스패치를 보여줍니다(/foo/**
가 /**
앞에 일치). 이는 매우 일반적이지만 요청을 일치시키는 유일한 방법은 아닙니다. 이 디스패치 프로세스의 가장 중요한 특징은 하나의 체인만 요청을 처리한다는 것입니다.
Figure 3. 스프링 보안 FilterChainProxy
는 일치하는 첫 번째 체인에 요청을 전송합니다.
사용자 정의 보안 구성이 없는 바닐라 Spring Boot 애플리케이션에는 여러 개의 필터 체인(보통 n=6)이 있습니다. 첫 번째(n-1) 체인은 /css/**
및 /images/**
와 같은 정적 리소스 패턴과 오류 보기를 무시하기 위해 존재합니다: /error
. (경로는 사용자가 SecurityProperties
구성 빈의 security.ignored
를 사용하여 제어할 수 있습니다.) 마지막 체인은 포괄 경로(/**
)와 일치하며 인증, 권한 부여, 예외 처리, 세션 처리, 헤더 쓰기 등에 대한 로직을 포함하는 보다 활성적입니다. 이 체인에는 기본적으로 총 11개의 필터가 있지만 일반적으로 사용자가 어떤 필터가 언제 사용되는지 신경 쓸 필요는 없습니다.
Note
Spring Security 내부의 모든 필터가 컨테이너에 알려지지 않는다는 사실은 특히 기본적으로
Filter
유형의 모든@Bean
이 컨테이너에 자동으로 등록되는 Spring Boot 애플리케이션에서 중요합니다. 따라서 보안 체인에 사용자 정의 필터를 추가하려면@Bean
으로 만들지 않거나 컨테이너 등록을 명시적으로 비활성화하는FilterRegistrationBean
으로 감싸야 합니다.
필터 체인 생성 및 사용자 지정
Spring Boot 애플리케이션의 기본 대체 필터 체인(/**
요청 일치기가 있는 체인)의 사전 정의된 순서는 SecurityProperties.BASIC_AUTH_ORDER
입니다. security.basic.enabled=false
를 설정하여 완전히 해제하거나, 이를 대체로 사용하고 더 낮은 순서로 다른 규칙을 정의할 수 있습니다. 후자를 사용하려면 다음과 같이 WebSecurityConfigurerAdapter
(또는 WebSecurityConfigurer
) 유형의 @Bean
을 추가하고 @Order
로 클래스를 장식합니다:
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/match1/**")
...;
}
}
이 빈을 사용하면 Spring Security가 새 필터 체인을 추가하고 폴백 전에 주문합니다.
많은 애플리케이션은 한 리소스 세트에 대해 다른 리소스 세트와 완전히 다른 액세스 규칙을 가지고 있습니다. 예를 들어, UI와 백킹 API를 호스팅하는 애플리케이션은 UI 부분에 대해서는 로그인 페이지로 리디렉션하는 쿠키 기반 인증을, API 부분에 대해서는 인증되지 않은 요청에 대해 401 응답을 보내는 토큰 기반 인증을 지원할 수 있습니다. 각 리소스 세트에는 고유한 순서와 고유한 요청 일치기를 가진 자체 WebSecurityConfigurerAdapter
가 있습니다. 매칭 규칙이 겹치는 경우 가장 빠른 순서의 필터 체인이 승리합니다.
Dispatch 및 Authorization Request 매칭
보안 필터 체인(또는 이에 상응하는 WebSecurityConfigurerAdapter
)에는 HTTP 요청에 적용할지 여부를 결정하는 데 사용되는 요청 일치기가 있습니다. 특정 필터 체인을 적용하기로 결정하면 다른 필터 체인은 적용되지 않습니다. 그러나 필터 체인 내에서 다음과 같이 HttpSecurity
구성자에 추가 매칭자를 설정하여 권한을 보다 세밀하게 제어할 수 있습니다:
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/match1/**")
.authorizeRequests()
.antMatchers("/match1/user").hasRole("USER")
.antMatchers("/match1/spam").hasRole("SPAM")
.anyRequest().isAuthenticated();
}
}
Spring Security를 구성할 때 가장 쉽게 저지르기 쉬운 실수 중 하나는 이러한 매칭자가 서로 다른 프로세스에 적용된다는 사실을 잊어버리는 것입니다. 하나는 전체 필터 체인에 대한 요청 매칭자이고 다른 하나는 적용할 액세스 규칙만 선택하는 것입니다.
애플리케이션 보안 규칙과 액추에이터 규칙 결합
관리 엔드포인트에 Spring Boot 액추에이터를 사용하는 경우 보안이 유지되기를 원할 것이며, 기본적으로 보안이 유지됩니다. 실제로 보안 애플리케이션에 액추에이터를 추가하자마자 액추에이터 엔드포인트에만 적용되는 추가 필터 체인이 생깁니다. 이 필터는 액추에이터 엔드포인트만 일치시키는 요청 매칭으로 정의되며, 기본 SecurityProperties
폴백 필터보다 5개 적은 ManagementServerProperties.BASIC_AUTH_ORDER
의 순서를 가지므로 폴백 전에 참조됩니다.
애플리케이션 보안 규칙을 액추에이터 엔드포인트에 적용하려면 액추에이터보다 먼저 정렬되고 모든 액추에이터 엔드포인트를 포함하는 요청 일치기가 있는 필터 체인을 추가할 수 있습니다. 액추에이터 엔드포인트에 대한 기본 보안 설정을 선호하는 경우 가장 쉬운 방법은 다음과 같이 액추에이터 필터보다 늦게, 그러나 폴백(예: ManagementServerProperties.BASIC_AUTH_ORDER + 1
)보다 일찍 자체 필터를 추가하는 것입니다:
@Configuration
@Order(ManagementServerProperties.BASIC_AUTH_ORDER + 1)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/foo/**")
...;
}
}
Note
웹 계층의 Spring Security는 현재 서블릿 API에 연결되어 있으므로, 임베디드 또는 기타 서블릿 컨테이너에서 애플리케이션을 실행할 때만 실제로 적용할 수 있습니다. 그러나 Spring MVC 또는 나머지 Spring 웹 스택에 묶여 있지 않으므로 모든 서블릿 애플리케이션(예: JAX-RS를 사용하는 애플리케이션)에서 사용할 수 있습니다.
Method Security
Spring Security는 웹 애플리케이션 보안을 지원할 뿐만 아니라 Java 메서드 실행에 액세스 규칙을 적용하는 기능도 지원합니다. Spring Security의 경우, 이것은 단지 다른 유형의 “보호된 리소스”입니다. 사용자에게는 접근 규칙이 동일한 형식의 ConfigAttribute
문자열(예: 역할 또는 표현식)을 사용하여 선언되지만 코드의 다른 위치에 있다는 것을 의미합니다. 첫 번째 단계는 예를 들어 애플리케이션의 최상위 구성에서 메서드 보안을 활성화하는 것입니다:
@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SampleSecureApplication {
}
그런 다음 메서드 리소스를 직접 장식할 수 있습니다:
@Service
public class MyService {
@Secured("ROLE_USER")
public String secure() {
return "Hello Security";
}
}
이 예제는 보안 메서드가 있는 서비스입니다. Spring이 이 유형의 @Bean
을 생성하면 프록시되고 호출자는 메서드가 실제로 실행되기 전에 보안 인터셉터를 거쳐야 합니다. 접근이 거부되면 호출자는 실제 메서드 결과 대신 AccessDeniedException
을 얻습니다.
메서드에 보안 제약을 적용하기 위해 사용할 수 있는 다른 어노테이션이 있는데, 특히 @PreAuthorize
와 @PostAuthorize
는 각각 메서드 매개변수와 반환값에 대한 참조를 포함하는 표현식을 작성할 수 있게 해줍니다.
Tip
웹 보안과 메소드 보안을 결합하는 것은 드문 일이 아닙니다. 필터 체인은 인증, 로그인 페이지 리디렉션 등과 같은 사용자 경험 기능을 제공하고 메서드 보안은 보다 세분화된 수준에서 보호 기능을 제공합니다.
스레드로 작업하기
현재 인증된 주체를 다양한 다운스트림 소비자들이 사용할 수 있도록 해야 하기 때문에 Spring Security는 기본적으로 스레드에 구속됩니다. 기본 빌딩 블록은 SecurityContext
이며, 여기에는 Authentication
이 포함될 수 있습니다(사용자가 로그인한 경우 명시적으로 authenticated
Authentication
이 됩니다). SecurityContextHolder
의 정적 편의 메서드를 통해 SecurityContext
에 접근하고 조작할 수 있으며, 이 메서드들은 차례로 ThreadLocal
을 조작합니다. 다음 예제는 이러한 배열을 보여줍니다:
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
assert(authentication.isAuthenticated);
사용자 애플리케이션 코드에서 이 작업을 수행하는 것은 일반적이지 않지만, 예를 들어 사용자 정의 인증 필터를 작성해야 하는 경우 유용할 수 있습니다(이 경우에도 Spring Security에는 SecurityContextHolder
를 사용할 필요가 없도록 사용할 수 있는 기본 클래스가 있지만).
웹 엔드포인트에서 현재 인증된 사용자에 대한 액세스가 필요한 경우, 다음과 같이 @RequestMapping
의 메서드 매개 변수를 사용할 수 있습니다:
@RequestMapping("/foo")
public String foo(@AuthenticationPrincipal User user) {
... // do stuff with user
}
이 어노테이션은 현재 Authentication
을 SecurityContext
에서 가져와서 getPrincipal()
메서드를 호출하여 메서드 파라미터를 산출합니다. Authentication
의 Principal
유형은 인증의 유효성을 검사하는 데 사용되는 AuthenticationManager
에 따라 달라지므로, 이는 사용자 데이터에 대한 유형 안전 참조를 얻는 데 유용한 작은 트릭이 될 수 있습니다.
Spring Security를 사용 중인 경우, HttpServletRequest
의 Principal
은 Authentication
유형이므로 이를 직접 사용할 수도 있습니다:
@RequestMapping("/foo")
public String foo(Principal principal) {
Authentication authentication = (Authentication) principal;
User = (User) authentication.getPrincipal();
... // do stuff with user
}
Spring Security를 사용하지 않을 때 작동하는 코드를 작성해야 할 때 유용할 수 있습니다( Authentication
클래스를 로드하는 것에 대해 좀 더 방어적이어야 함).
보안 메서드 비동기 처리
SecurityContext
는 스레드에 바인딩되어 있으므로 보안 메서드를 호출하는 백그라운드 처리(예: @Async
사용)를 수행하려면 컨텍스트가 전파되는지 확인해야 합니다. 이는 백그라운드에서 실행되는 태스크(Runnable
, Callable
등)로 SecurityContext
를 래핑하는 것으로 요약됩니다. 스프링 시큐리티는 이 작업을 더 쉽게 하기 위해 Runnable
과 Callable
에 대한 래퍼와 같은 몇 가지 도우미를 제공합니다. SecurityContext
를 @Async
메서드에 전파하려면 AsyncConfigurer
를 제공하고 Executor
의 유형이 올바른지 확인해야 합니다:
@Configuration
public class ApplicationConfiguration extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
return new DelegatingSecurityContextExecutorService(Executors.newFixedThreadPool(5));
}
}
댓글남기기