概述
介绍
作为一个配置HttpSecurity
的SecurityConfigurer
,RequestCacheConfigurer
的配置任务如下 :
- 配置如下安全过滤器
Filter
RequestCacheAwareFilter
- 属性
RequestCache requestCache
的设置流程如下 :-
- 首先尝试从共享对象获取
-
- 其次尝试从
bean IoC
容器获取
- 其次尝试从
-
- 最后尝试使用缺省值
HttpSessionRequestCache
- 针对以下几种情况之外的请求不会被缓存
/**/favicon.*
XMLHttpRequest
application/json
GET /**
在csrf
保护开启时请求也不会被缓存
- 最后尝试使用缺省值
-
- 属性
继承关系
使用
// HttpSecurity 代码片段
public RequestCacheConfigurer<HttpSecurity> requestCache() throws Exception {
return getOrApply(new RequestCacheConfigurer<>());
}
源代码
源代码版本 Spring Security Config 5.1.4.RELEASE
package org.springframework.security.config.annotation.web.configurers;
// 省略 imports
public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<RequestCacheConfigurer<H>, H> {
public RequestCacheConfigurer() {
}
/**
* Allows explicit configuration of the RequestCache to be used. Defaults to
* try finding a RequestCache as a shared object. Then falls back to a
* HttpSessionRequestCache.
*
* @param requestCache the explicit RequestCache to use
* @return the RequestCacheConfigurer for further customization
*/
public RequestCacheConfigurer<H> requestCache(RequestCache requestCache) {
getBuilder().setSharedObject(RequestCache.class, requestCache);
return this;
}
@Override
public H disable() {
getBuilder().setSharedObject(RequestCache.class, new NullRequestCache());
return super.disable();
}
@Override
public void init(H http) throws Exception {
http.setSharedObject(RequestCache.class, getRequestCache(http));
}
@Override
public void configure(H http) throws Exception {
// 创建 RequestCache
RequestCache requestCache = getRequestCache(http);
// 创建 RequestCacheAwareFilter
RequestCacheAwareFilter requestCacheFilter = new RequestCacheAwareFilter(
requestCache);
requestCacheFilter = postProcess(requestCacheFilter);
http.addFilter(requestCacheFilter);
}
/**
* Gets the RequestCache to use. If one is defined using
* #requestCache(org.springframework.security.web.savedrequest.RequestCache),
* then it is used. Otherwise, an attempt to find a RequestCache shared object
* is made. If that fails, an HttpSessionRequestCache is used
*
* @param http the HttpSecurity to attempt to fined the shared object
* @return the RequestCache to use
*/
private RequestCache getRequestCache(H http) {
// 首先尝试从共享对象获取 RequestCache
RequestCache result = http.getSharedObject(RequestCache.class);
if (result != null) {
return result;
}
// 其次尝试从bean容器中获取 RequestCache
result = getBeanOrNull(RequestCache.class);
if (result != null) {
return result;
}
// 最后尝试使用缺省 RequestCache : HttpSessionRequestCache
HttpSessionRequestCache defaultCache = new HttpSessionRequestCache();
defaultCache.setRequestMatcher(createDefaultSavedRequestMatcher(http));
return defaultCache;
}
private <T> T getBeanOrNull(Class<T> type) {
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
if (context == null) {
return null;
}
try {
return context.getBean(type);
} catch (NoSuchBeanDefinitionException e) {
return null;
}
}
@SuppressWarnings("unchecked")
private RequestMatcher createDefaultSavedRequestMatcher(H http) {
ContentNegotiationStrategy contentNegotiationStrategy = http
.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher(
"/**/favicon.*"));
MediaTypeRequestMatcher jsonRequest = new MediaTypeRequestMatcher(
contentNegotiationStrategy, MediaType.APPLICATION_JSON);
jsonRequest.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
RequestMatcher notJson = new NegatedRequestMatcher(jsonRequest);
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
List<RequestMatcher> matchers = new ArrayList<>();
if (isCsrfEnabled) {
RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET");
matchers.add(0, getRequests);
}
matchers.add(notFavIcon);
matchers.add(notJson);
matchers.add(notXRequestedWith);
return new AndRequestMatcher(matchers);
}
}