Po zmaganiach z licznymi rozwiązaniami zamieszczonymi w tej odpowiedzi, aby spróbować uzyskać coś działającego podczas korzystania z <http>
konfiguracji przestrzeni nazw, w końcu znalazłem podejście, które faktycznie działa w moim przypadku użycia. Właściwie nie wymagam, żeby Spring Security nie rozpoczynał sesji (ponieważ używam sesji w innych częściach aplikacji), tylko żeby w ogóle nie "pamiętał" uwierzytelnienia w sesji (powinno być ponownie sprawdzone każde żądanie).
Przede wszystkim nie byłem w stanie dowiedzieć się, jak wykonać technikę „implementacji zerowej” opisaną powyżej. Nie było jasne, czy masz ustawić securityContextRepository null
na implementację bez operacji . Ten pierwszy nie działa, ponieważ NullPointerException
zostaje wrzucony do środka SecurityContextPersistenceFilter.doFilter()
. Jeśli chodzi o implementację no-op, próbowałem zaimplementować ją w najprostszy sposób, jaki mogłem sobie wyobrazić:
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;
}
}
To nie działa w mojej aplikacji z powodu dziwnego ClassCastException
związku z response_
typem.
Nawet zakładając, że udało mi się znaleźć implementację, która działa (po prostu nie przechowując kontekstu w sesji), nadal istnieje problem, jak wstrzyknąć ją do filtrów zbudowanych przez <http>
konfigurację. Nie można po prostu wymienić filtra na SECURITY_CONTEXT_FILTER
miejscu, zgodnie z dokumentacją . Jedynym sposobem, w jaki znalazłem zaczepienie w tym, SecurityContextPersistenceFilter
co powstaje pod okładkami, było napisanie brzydkiej ApplicationContextAware
fasoli:
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());
}
}
}
}
}
}
}
W każdym razie do rozwiązania, które faktycznie działa, choć jest bardzo hakerskie. Po prostu użyj a, Filter
który usuwa wpis sesji, którego HttpSessionSecurityContextRepository
szuka, gdy robi swoje:
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_);
}
}
Następnie w konfiguracji:
<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>