Після боротьби з численними рішеннями, розміщеними в цій відповіді, щоб спробувати отримати щось працююче при використанні <http>конфігурації простору імен, я нарешті знайшов підхід, який насправді працює для мого випадку використання. Насправді я не вимагаю, щоб Spring Security не запускав сеанс (оскільки я використовую сесію в інших частинах програми), просто щоб він взагалі не "запам'ятовував" автентифікацію в сеансі (її слід повторно перевірити кожен запит).
Для початку я не зміг зрозуміти, як виконати описану вище техніку "нульової реалізації". Не було зрозуміло, чи потрібно ви встановити SecurityContextRepository на nullабо нереалізовану реалізацію. Колишній не працює, тому що NullPointerExceptionпотрапляє всередину SecurityContextPersistenceFilter.doFilter(). Що стосується безпрограшної реалізації, я намагався реалізувати найпростішим способом, який я міг уявити:
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;
}
}
Це не працює в моєму додатку, оскільки це дивно ClassCastExceptionпов'язане з response_типом.
Навіть припускаючи, що мені вдалося знайти реалізацію, яка працює (просто не зберігаючи контекст у сесії), все ще існує проблема, як ввести це у фільтри, побудовані за допомогою <http>конфігурації. Ви не можете просто замінити фільтр у SECURITY_CONTEXT_FILTERположенні відповідно до документів . Єдиний спосіб, який я знайшов, щоб зачепитися за SecurityContextPersistenceFilterте, що створюється під обкладинками, - це написати некрасиві ApplicationContextAwareбоби:
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());
}
}
}
}
}
}
}
У будь-якому випадку, до рішення, яке насправді працює, хоч і дуже хакерське. Просто скористайтеся Filterсимволом, який видаляє запис сеансу, який HttpSessionSecurityContextRepositoryшукає, коли він робить свою справу:
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_);
}
}
Потім у конфігурації:
<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>