Sau khi vật lộn với nhiều giải pháp được đăng trong câu trả lời này, để cố gắng làm cho một cái gì đó hoạt động khi sử dụng <http>
cấu hình không gian tên, cuối cùng tôi đã tìm thấy một cách tiếp cận thực sự phù hợp với trường hợp sử dụng của tôi. Tôi không thực sự yêu cầu Spring Security không bắt đầu một phiên (vì tôi sử dụng phiên trong các phần khác của ứng dụng), chỉ là nó hoàn toàn không "nhớ" xác thực trong phiên (nó nên được kiểm tra lại mọi yêu cầu).
Để bắt đầu, tôi không thể tìm ra cách thực hiện kỹ thuật "triển khai null" được mô tả ở trên. Không rõ liệu bạn có nên đặt securityContextRepository thành null
hay không. Cái trước không hoạt động vì một cái NullPointerException
bị ném vào bên trong SecurityContextPersistenceFilter.doFilter()
. Đối với việc triển khai no-op, tôi đã thử triển khai theo cách đơn giản nhất mà tôi có thể tưởng tượng:
public class NullSpringSecurityContextRepository implements SecurityContextRepository {
@Override
public SecurityContext loadContext(final HttpRequestResponseHolder requestResponseHolder_) {
return SecurityContextHolder.createEmptyContext();
}
@Override
public void saveContext(final SecurityContext context_, final HttpServletRequest request_,
final HttpServletResponse response_) {
}
@Override
public boolean containsContext(final HttpServletRequest request_) {
return false;
}
}
Điều này không hoạt động trong ứng dụng của tôi, vì có một số điều kỳ lạ liên ClassCastException
quan đến response_
loại.
Ngay cả khi giả sử tôi đã quản lý để tìm thấy một triển khai hoạt động (đơn giản là không lưu trữ ngữ cảnh trong phiên), vẫn còn vấn đề về cách đưa nó vào các bộ lọc được xây dựng bởi <http>
cấu hình. Bạn không thể chỉ cần thay thế bộ lọc tại SECURITY_CONTEXT_FILTER
vị trí, theo tài liệu . Cách duy nhất tôi tìm thấy để móc vào SecurityContextPersistenceFilter
cái được tạo dưới bìa là viết một ApplicationContextAware
hạt đậu xấu xí :
public class SpringSecuritySessionDisabler implements ApplicationContextAware {
private final Logger logger = LoggerFactory.getLogger(SpringSecuritySessionDisabler.class);
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(final ApplicationContext applicationContext_) throws BeansException {
applicationContext = applicationContext_;
}
public void disableSpringSecuritySessions() {
final Map<String, FilterChainProxy> filterChainProxies = applicationContext
.getBeansOfType(FilterChainProxy.class);
for (final Entry<String, FilterChainProxy> filterChainProxyBeanEntry : filterChainProxies.entrySet()) {
for (final Entry<String, List<Filter>> filterChainMapEntry : filterChainProxyBeanEntry.getValue()
.getFilterChainMap().entrySet()) {
final List<Filter> filterList = filterChainMapEntry.getValue();
if (filterList.size() > 0) {
for (final Filter filter : filterList) {
if (filter instanceof SecurityContextPersistenceFilter) {
logger.info(
"Found SecurityContextPersistenceFilter, mapped to URL '{}' in the FilterChainProxy bean named '{}', setting its securityContextRepository to the null implementation to disable caching of authentication",
filterChainMapEntry.getKey(), filterChainProxyBeanEntry.getKey());
((SecurityContextPersistenceFilter) filter).setSecurityContextRepository(
new NullSpringSecurityContextRepository());
}
}
}
}
}
}
}
Dù sao, đối với giải pháp thực sự hoạt động, mặc dù rất khó. Chỉ cần sử dụng một lệnh Filter
xóa mục nhập phiên mà mục này HttpSessionSecurityContextRepository
sẽ tìm kiếm khi nó thực hiện nhiệm vụ của mình:
public class SpringSecuritySessionDeletingFilter extends GenericFilterBean implements Filter {
@Override
public void doFilter(final ServletRequest request_, final ServletResponse response_, final FilterChain chain_)
throws IOException, ServletException {
final HttpServletRequest servletRequest = (HttpServletRequest) request_;
final HttpSession session = servletRequest.getSession();
if (session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY) != null) {
session.removeAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
}
chain_.doFilter(request_, response_);
}
}
Sau đó, trong cấu hình:
<bean id="springSecuritySessionDeletingFilter"
class="SpringSecuritySessionDeletingFilter" />
<sec:http auto-config="false" create-session="never"
entry-point-ref="authEntryPoint">
<sec:intercept-url pattern="/**"
access="IS_AUTHENTICATED_REMEMBERED" />
<sec:intercept-url pattern="/static/**" filters="none" />
<sec:custom-filter ref="myLoginFilterChain"
position="FORM_LOGIN_FILTER" />
<sec:custom-filter ref="springSecuritySessionDeletingFilter"
before="SECURITY_CONTEXT_FILTER" />
</sec:http>