春季安全6.2.5
应用程序混合了页面 (JSP) 和 API 端点。使用表单登录和自定义登录页面。
场景:用户打开了 2 个浏览器选项卡。首先,一个页面进行重复的 API 调用以获取 JSON 响应(轮询)。在另一个选项卡中,他访问了不同的页面。在第二个选项卡中,用户注销(这会将他带到登录页面)。一段时间后,用户再次登录(在第二个浏览器选项卡中);
RequestCache
开始将用户带回上次请求所在的位置,但这是一个 API 调用(从第一个 API 轮询、选项卡开始),因此用户会看到原始 JSON 响应而不是页面。
由于轮询,请求缓存已保存 API 请求。我想排除 API 调用保存在缓存中。默认的
RequestCache
实现 (HttpSessionRequestCache
) 设置一个匹配器来提供帮助,但它不知道我们的端点命名约定。问题是,我找不到一种方法来修改 RequestMatcher
中的 RequestCacheConfigurer
。我不想复制 RequestCacheConfigurer.createDefaultSavedRequestMatcher()
中的所有设置。
是否有一种简单的方法来扩展缓存的
RequestMatcher
,或者另一种方法来控制缓存哪些请求?
截至目前(Spring Security 6.2),无法扩展默认的请求缓存匹配器,只能完全替换它。 此 GitHub 问题中正在持续讨论支持扩展的想法。
以下是将我自己的自定义模式添加到默认请求匹配器以进行缓存所需执行的操作。遗憾的是,它主要是
org.springframework.security.config.annotation.web.configurers.RequestCacheConfigurer
中代码的副本
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.requestCache(c -> configureRequestCache(c, http));
}
private void configureRequestCache(RequestCacheConfigurer<HttpSecurity> configurer, HttpSecurity httpSecurity) {
HttpSessionRequestCache cache = new HttpSessionRequestCache();
cache.setRequestMatcher(createSavedRequestMatcher(httpSecurity));
configurer.requestCache(cache);
}
private RequestMatcher createSavedRequestMatcher(HttpSecurity http) {
List<RequestMatcher> matchers = new ArrayList<>();
RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher("/**/favicon.*"));
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
@SuppressWarnings("unchecked")
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
if (isCsrfEnabled) {
RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET");
matchers.add(0, getRequests);
}
matchers.add(notFavIcon);
matchers.add(notMatchingMediaType(http, MediaType.APPLICATION_JSON));
matchers.add(notXRequestedWith);
matchers.add(notMatchingMediaType(http, MediaType.MULTIPART_FORM_DATA));
matchers.add(notMatchingMediaType(http, MediaType.TEXT_EVENT_STREAM));
// Exclude our API endpoints from the matcher
RequestMatcher notAPI = new NegatedRequestMatcher(new AntPathRequestMatcher("/**/api/**", "GET"));
matchers.add(notAPI);
return new AndRequestMatcher(matchers);
}
我的应用程序唯一自定义的部分是评论下的两行
// Exclude our API endpoints from the matcher
。