Setelah berjuang dengan banyak solusi yang diposting dalam jawaban ini, untuk mencoba mendapatkan sesuatu yang berfungsi saat menggunakan <http>
konfigurasi namespace, saya akhirnya menemukan pendekatan yang benar-benar berfungsi untuk kasus penggunaan saya. Saya sebenarnya tidak mengharuskan Spring Security tidak memulai sesi (karena saya menggunakan sesi di bagian lain aplikasi), hanya saja Spring Security tidak "mengingat" otentikasi dalam sesi sama sekali (harus diperiksa ulang setiap permintaan).
Untuk memulainya, saya tidak dapat menemukan cara untuk melakukan teknik "implementasi nol" yang dijelaskan di atas. Tidak jelas apakah Anda harus menyetel securityContextRepository ke null
atau ke implementasi tanpa operasi. Yang pertama tidak berfungsi karena a NullPointerException
terlempar ke dalam SecurityContextPersistenceFilter.doFilter()
. Sedangkan untuk implementasi tanpa operasi, saya mencoba menerapkan dengan cara yang paling sederhana yang dapat saya bayangkan:
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;
}
}
Ini tidak berfungsi di aplikasi saya, karena ada yang aneh ClassCastException
dengan response_
jenisnya.
Bahkan dengan asumsi saya berhasil menemukan implementasi yang berfungsi (dengan tidak menyimpan konteks dalam sesi), masih ada masalah tentang bagaimana menyuntikkannya ke dalam filter yang dibangun oleh <http>
konfigurasi. Anda tidak bisa begitu saja mengganti filter pada SECURITY_CONTEXT_FILTER
posisi tersebut, sesuai dengan dokumen . Satu-satunya cara saya menemukan untuk mengaitkan SecurityContextPersistenceFilter
yang dibuat di bawah sampul adalah dengan menulis ApplicationContextAware
kacang jelek :
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());
}
}
}
}
}
}
}
Bagaimanapun, ke solusi yang benar-benar berfungsi, meskipun sangat hackish. Cukup gunakan Filter
yang menghapus entri sesi yang HttpSessionSecurityContextRepository
dicari saat melakukan tugasnya:
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_);
}
}
Kemudian di konfigurasi:
<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>