스프링 보안 필터 체인은 매우 복잡하고 유연한 엔진입니다.
체인의 주요 필터는 (순서대로)
- SecurityContextPersistenceFilter (JSESSIONID에서 인증을 복원 함)
- UsernamePasswordAuthenticationFilter (인증 수행)
- ExceptionTranslationFilter (FilterSecurityInterceptor의 보안 예외 포착)
- FilterSecurityInterceptor (인증 및 권한 부여 예외가 발생할 수 있음)
상기 찾고 현재 안정적인 릴리스 4.2.1 문서 , 섹션 13.3 필터 순서 는 전체 필터 체인의 필터 구성을 볼 수 있었다 :
13.3 필터 주문
필터가 체인에 정의 된 순서는 매우 중요합니다. 실제로 사용중인 필터에 관계없이 순서는 다음과 같아야합니다.
다른 프로토콜로 경로 재지 정해야 할 수 있으므로 ChannelProcessingFilter
SecurityContextPersistenceFilter- 웹 요청 시작시 SecurityContextHolder에서 SecurityContext를 설정할 수 있으며 웹 요청이 종료되면 SecurityContext에 대한 변경 사항을 HttpSession에 복사 할 수 있습니다 (다음 웹 요청에 사용할 준비가 됨).
ConcurrentSessionFilter 는 SecurityContextHolder 기능을 사용하고 프린시 펄의 진행중인 요청을 반영하기 위해 SessionRegistry를 업데이트해야하기 때문에
유효한 인증 요청 토큰을 포함하도록 SecurityContextHolder를 수정할 수 있도록 인증 처리 메커니즘 (
UsernamePasswordAuthenticationFilter , CasAuthenticationFilter ,
BasicAuthenticationFilter 등)
SecurityContextHolderAwareRequestFilter , 당신은 당신의 서블릿 컨테이너에 HttpServletRequestWrapper 스프링 보안 인식을 설치하는 데 사용하는 경우
JaasApiIntegrationFilter , 만약 JaasAuthenticationToken가 SecurityContextHolder에있는이는 JaasAuthenticationToken의 주제로 FilterChain을 처리합니다
RememberMeAuthenticationFilter 이전의 인증 처리 메커니즘이 SecurityContextHolder를 업데이트하지 않고 요청에서 remember-me 서비스를 수행 할 수있는 쿠키를 제시하는 경우 적절한 기억 된 인증 오브젝트가 거기에 배치됩니다.
AnonymousAuthenticationFilter- 이전의 인증 처리 메커니즘이 SecurityContextHolder를 업데이트하지 않은 경우 익명의 인증 객체가 거기에있게됩니다.
ExceptionTranslationFilter- HTTP 오류 응답을 리턴하거나 적절한 AuthenticationEntryPoint를 시작할 수 있도록 모든 스프링 보안 예외를 포착합니다.
FilterSecurityInterceptor- 웹 URI를 보호하고 액세스가 거부 될 때 예외를 발생시킵니다.
이제 여러분의 질문에 따라 하나씩 시도해 보겠습니다.
이 필터가 어떻게 사용되는지 혼란 스럽습니다. Spring에서 제공 한 양식 로그인의 경우 UsernamePasswordAuthenticationFilter는 / login에만 사용되며 후자의 필터는 사용되지 않습니까? 양식 로그인 네임 스페이스 요소가 이러한 필터를 자동 구성합니까? 로그인하지 않은 URL에 대한 모든 요청 (인증 여부)이 FilterSecurityInterceptor에 도달합니까?
일단 구성하면 <security-http>
섹션을 각 섹션마다 최소한 하나의 인증 메커니즘을 제공해야합니다. 이것은 방금 참조한 Spring Security 문서의 13.3 필터 순서 섹션에서 그룹 4와 일치하는 필터 중 하나 여야합니다.
이것은 구성 가능한 최소 유효한 security : http 요소입니다.
<security:http authentication-manager-ref="mainAuthenticationManager"
entry-point-ref="serviceAccessDeniedHandler">
<security:intercept-url pattern="/sectest/zone1/**" access="hasRole('ROLE_ADMIN')"/>
</security:http>
그냥 필터 체인 프록시에서 이러한 필터를 구성하면됩니다.
{
"1": "org.springframework.security.web.context.SecurityContextPersistenceFilter",
"2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter",
"3": "org.springframework.security.web.header.HeaderWriterFilter",
"4": "org.springframework.security.web.csrf.CsrfFilter",
"5": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter",
"6": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter",
"7": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter",
"8": "org.springframework.security.web.session.SessionManagementFilter",
"9": "org.springframework.security.web.access.ExceptionTranslationFilter",
"10": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor"
}
참고 : FilterChainProxy를 @Autowires하고 내용을 반환하는 간단한 RestController를 만들어서 얻습니다.
@Autowired
private FilterChainProxy filterChainProxy;
@Override
@RequestMapping("/filterChain")
public @ResponseBody Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){
return this.getSecurityFilterChainProxy();
}
public Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){
Map<Integer, Map<Integer, String>> filterChains= new HashMap<Integer, Map<Integer, String>>();
int i = 1;
for(SecurityFilterChain secfc : this.filterChainProxy.getFilterChains()){
//filters.put(i++, secfc.getClass().getName());
Map<Integer, String> filters = new HashMap<Integer, String>();
int j = 1;
for(Filter filter : secfc.getFilters()){
filters.put(j++, filter.getClass().getName());
}
filterChains.put(i++, filters);
}
return filterChains;
}
여기서는 <security:http>
하나의 최소 구성으로 요소를 선언하는 것만으로 모든 기본 필터가 포함되지만 인증 유형은 13.3 필터 순서 섹션의 네 번째 그룹이 아닙니다. 따라서 실제로 security:http
요소 를 선언하는 것만으로 SecurityContextPersistenceFilter, ExceptionTranslationFilter 및 FilterSecurityInterceptor가 자동 구성됨을 의미합니다.
실제로 하나의 인증 처리 메커니즘을 구성해야하며 보안 네임 스페이스 Bean 처리에도이를 요구하여 시작 중에 오류가 발생하지만 시작점 참조 속성을 추가하여 무시할 수 있습니다. <http:security>
<form-login>
구성에 기본 을 추가하면 다음 과 같이됩니다.
<security:http authentication-manager-ref="mainAuthenticationManager">
<security:intercept-url pattern="/sectest/zone1/**" access="hasRole('ROLE_ADMIN')"/>
<security:form-login />
</security:http>
이제 filterChain은 다음과 같습니다.
{
"1": "org.springframework.security.web.context.SecurityContextPersistenceFilter",
"2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter",
"3": "org.springframework.security.web.header.HeaderWriterFilter",
"4": "org.springframework.security.web.csrf.CsrfFilter",
"5": "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter",
"6": "org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter",
"7": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter",
"8": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter",
"9": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter",
"10": "org.springframework.security.web.session.SessionManagementFilter",
"11": "org.springframework.security.web.access.ExceptionTranslationFilter",
"12": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor"
}
이제이 두 필터 org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter 및 org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter가 FilterChainProxy에서 작성 및 구성됩니다.
이제 질문은 다음과 같습니다.
Spring에서 제공 한 양식 로그인의 경우 UsernamePasswordAuthenticationFilter는 / login에만 사용되며 후자의 필터는 사용되지 않습니까?
예, 요청이 UsernamePasswordAuthenticationFilter url과 일치하는 경우 로그인 처리 메커니즘을 완료하는 데 사용됩니다. 이 URL을 구성하거나 모든 요청과 일치하도록 동작을 변경할 수도 있습니다.
동일한 FilterchainProxy (HttpBasic, CAS 등)에 둘 이상의 인증 처리 메커니즘을 구성 할 수도 있습니다.
양식 로그인 네임 스페이스 요소가 이러한 필터를 자동 구성합니까?
아니요, form-login 요소는 UsernamePasswordAUthenticationFilter를 구성하고 로그인 페이지 URL을 제공하지 않는 경우 org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter도 구성하여 간단한 자동 생성 된 로그인으로 끝납니다. 페이지.
다른 필터는 기본적으로 속성 <security:http>
이없는 요소를 작성하여 자동 구성됩니다 security:"none"
.
로그인하지 않은 URL에 대한 모든 요청 (인증 여부)이 FilterSecurityInterceptor에 도달합니까?
요청이 요청 된 URL에 도달 할 수있는 권한이 있는지 여부를 처리하는 요소이므로 모든 요청이 도달해야합니다. 그러나 이전에 처리 된 일부 필터는 호출하지 않는 필터 체인 처리를 중지 할 수 있습니다 FilterChain.doFilter(request, response);
. 예를 들어, 요청에 csrf 매개 변수가없는 경우 CSRF 필터가 필터 체인 처리를 중지 할 수 있습니다.
로그인에서 검색되는 JWT 토큰으로 REST API를 보호하려면 어떻게해야합니까? 두 개의 네임 스페이스 구성 http 태그를 구성해야합니까? 와 함께 / login에 UsernamePasswordAuthenticationFilter
대한 다른 하나와 custom과 함께 REST URL에 대한 다른 하나 JwtAuthenticationFilter
.
아니, 당신은 이런 식으로 강제로하지 않습니다. 둘 다 선언 할 수 UsernamePasswordAuthenticationFilter
와를 JwtAuthenticationFilter
같은 HTTP 요소에 있지만,이 필터의 각각의 구체적인 동작에 따라 달라집니다. 두 가지 방법 모두 가능하며, 어떤 방법을 선택해야하는지에 따라 선호도가 달라집니다.
두 개의 http 요소를 구성하면 두 개의 springSecurityFitlerChain이 생성됩니까?
예, 맞습니다
양식 로그인을 선언 할 때까지 UsernamePasswordAuthenticationFilter가 기본적으로 해제되어 있습니까?
예, 게시 한 각 구성에서 발생하는 필터에서 볼 수 있습니다
SecurityContextPersistenceFilter를 SecurityContextPersistenceFilter로 바꾸려면 어떻게해야합니까? JSESSIONID가 아닌 기존 JWT 토큰에서 인증을 얻습니까?
에서 SecurityStrategyPersistenceFilter를 피하고 세션 전략 을 구성하면 됩니다 <http:element>
. 다음과 같이 구성하십시오.
<security:http create-session="stateless" >
또는이 경우 <security:http>
요소 내부에서 다른 필터로 덮어 쓸 수 있습니다 .
<security:http ...>
<security:custom-filter ref="myCustomFilter" position="SECURITY_CONTEXT_FILTER"/>
</security:http>
<beans:bean id="myCustomFilter" class="com.xyz.myFilter" />
편집하다:
"동일한 FilterchainProxy에 둘 이상의 인증 처리 메커니즘을 구성 할 수도 있습니다"에 대한 한 가지 질문입니다. 여러 개의 (Spring 구현) 인증 필터를 선언하는 경우 후자가 첫 번째 인증에 의해 수행 된 인증을 덮어 쓰게됩니까? 이것이 여러 인증 공급자를 갖는 것과 어떤 관련이 있습니까?
이것은 마지막으로 각 필터 자체의 구현에 달려 있지만, 후자의 인증 필터는 적어도 이전의 필터에 의해 만들어진 이전의 인증을 덮어 쓸 수 있다는 사실입니다.
그러나 이것은 반드시 일어나지 않을 것입니다. 보안 REST 서비스에는 Http 헤더 또는 요청 본문 모두에 제공 될 수있는 일종의 권한 부여 토큰을 사용하는 프로덕션 사례가 있습니다. 따라서 하나의 경우 Http 헤더와 다른 나머지 요청의 요청 본문에서 해당 토큰을 복구하는 두 개의 필터를 구성합니다. 하나의 http 요청이 Http 헤더와 요청 본문 내부 모두에서 해당 인증 토큰을 제공하면 두 필터 모두 관리자에게 위임하는 인증 메커니즘을 실행하려고 시도하지만 요청이 있는지 확인하는 것은 쉽게 피할 수 있습니다. 시작시 바로 인증doFilter()
각 필터 메소드 .
둘 이상의 인증 필터를 갖는 것은 둘 이상의 인증 공급자를 갖는 것과 관련이 있지만 강제하지는 않습니다. 이전에 노출 된 경우 두 개의 인증 필터가 있지만 두 필터 모두 동일한 유형의 Authentication 객체를 생성하므로 두 경우 모두 인증 관리자가 동일한 제공자에게 위임하기 때문에 하나의 인증 제공자 만 있습니다.
그리고 이와 반대로, 나는 하나의 UsernamePasswordAuthenticationFilter를 게시하는 시나리오가 있지만 사용자 자격 증명은 모두 DB 또는 LDAP에 포함될 수 있으므로 두 개의 UsernamePasswordAuthenticationToken 지원 공급자를 가지고 있으며 AuthenticationManager는 필터의 모든 인증 시도를 필터에서 공급자에게 위임합니다. 자격 증명의 유효성을 검사합니다.
따라서 인증 필터 수는 인증 공급자 수를 결정하지 않으며 공급자 수는 필터 수를 결정하지 않습니다.
또한 설명서에는 SecurityContextPersistenceFilter가 스레드 풀링으로 인해 중요한 SecurityContext를 정리해야한다고 명시되어 있습니다. 생략하거나 사용자 지정 구현을 제공하는 경우 수동으로 청소를 구현해야합니까? 체인을 커스터마이징 할 때 더 비슷한 점이 있습니까?
필자는이 필터를주의 깊게 살펴 보지 않았지만 마지막 질문 후에 구현을 확인했으며 일반적으로 Spring에서와 같이 거의 모든 것이 구성, 확장 또는 덮어 쓸 수 있습니다.
SecurityContextPersistenceFilter의 A의 대표 SecurityContextRepository 구현 SecurityContext에 대한 검색. 기본적으로 HttpSessionSecurityContextRepository 가 사용되지만 이는 필터 생성자 중 하나를 사용하여 변경할 수 있습니다. 따라서 사용자의 요구에 맞는 SecurityContextRepository를 작성하고 SecurityContextPersistenceFilter에서 구성하는 것이 좋을 것입니다. 처음부터 모두 시작하기보다는 입증 된 동작을 신뢰하십시오.