Nach dem Kampf mit den zahlreichen Lösungen in dieser Antwort geschrieben, um zu versuchen, etwas funktioniert bei der Verwendung der Namespace-Konfiguration <http>
, fand ich endlich einen Ansatz, der tatsächlich für meinen Anwendungsfall funktioniert.Ich benötige eigentlich nicht, dass Spring Security keine Sitzung startet (weil ich Sitzung in anderen Teilen der Anwendung verwende), nur dass es sich nicht an die Authentifizierung in der Sitzung "erinnert" (es sollte erneut überprüft werden) jede Anfrage).
Zu Beginn war ich nicht in der Lage, herauszufinden, wie man die oben beschriebene "Nullimplementierung" -Technik durchführt. Es war nicht klar, ob Sie das securityContextRepository auf null
oder auf eine No-Op-Implementierung setzen sollten. Das ehemalige funktioniert nicht, weil ein NullPointerException
innerhalb SecurityContextPersistenceFilter.doFilter()
geworfen wird. Da für die Umsetzung no-op, habe ich versucht, auf einfachste Art und Weise der Umsetzung könnte ich mir vorstellen:
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;
}
}
Das ist nicht in meiner Anwendung nicht funktioniert, weil einige seltsame ClassCastException
mit dem response_
Art zu tun.
Selbst wenn ich eine Implementierung gefunden habe, die funktioniert (indem ich einfach nicht den Kontext in der Sitzung ablege), gibt es immer noch das Problem, wie man das in die von der <http>
-Konfiguration erstellten Filter einspeist. Sie können den Filter nicht einfach an der Position SECURITY_CONTEXT_FILTER
gemäß der docs ersetzen. Der einzige Weg, ich in die SecurityContextPersistenceFilter
Haken gefunden, die unter der Decke geschaffen war eine hässliche ApplicationContextAware
Bohne zu schreiben:
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());
}
}
}
}
}
}
}
Wie auch immer, zu der Lösung, die tatsächlich funktioniert, wenn auch sehr hackish. Verwenden Sie einfach einen Filter
, der die Sitzung Eintrag löscht, dass die HttpSessionSecurityContextRepository
für aussieht, wenn es hat seine Sache:
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_);
}
}
Dann in der Konfiguration:
<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>
Das hat nicht funktioniert, wie ich es mir vorgestellt habe. Stattdessen gibt es einen Kommentar, der zwischen "niemals" und "staatenlos" unterscheidet. Mit "nie" erstellte meine App immer noch Sitzungen. Mit "statuslos" wurde meine App tatsächlich zustandslos und ich musste keine der in anderen Antworten erwähnten Überschreibungen implementieren. Siehe das JIRA-Problem hier: https://jira.springsource.org/browse/SEC-1424 – sappenin