Після боротьби з численними рішеннями, розміщеними в цій відповіді, щоб спробувати отримати щось працююче при використанні <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>