Spring 工作 sessionRegistry 不使用 CAS 验证
Spring Working sessionRegistry not working with CAS auth
我正在使用 Spring Boot 2.1。6.RELEASE。
我需要使角色已更改的用户的会话过期。
我试图使用 sessionRegistry 但它不起作用,我不明白为什么...
这是我的 SecurityConfigurer class:
/**
* Configuració de seguretat
*/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
public static final String WEB = "\/((?!api).*)";
public static final String API = "/api/**";
@Order(1)
@Configuration
public static class RestApiWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Resource(name = "restAuthenticationFilter")
private Filter restAuthenticationFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher(API)
.csrf().disable()
.antMatcher(API)
.addFilterBefore(restAuthenticationFilter, CsrfFilter.class)
.antMatcher(API)
.authorizeRequests()
.antMatchers(API).authenticated()
.and()
.antMatcher(API)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
}
}
@Order(2)
@Configuration
public static class ApplicacionWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
private final CasProperties casProperties;
private final AuthenticationUserDetailsService<CasAssertionAuthenticationToken> casUsuariDetailsService;
private final UserDetailsService usuariDetailsService;
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}
@Autowired
public ApplicacionWebSecurityConfigurerAdapter(
CasProperties casProperties,
AuthenticationUserDetailsService<CasAssertionAuthenticationToken> casUsuariDetailsService,
@Qualifier("casUserDetailsService")
UserDetailsService usuariDetailsService) {
this.casProperties = casProperties;
this.casUsuariDetailsService = casUsuariDetailsService;
this.usuariDetailsService = usuariDetailsService;
}
@Bean
public ServiceProperties serviceProperties() throws UnknownHostException {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(getUrlWithHostName(casProperties.getValidateUrl()));
serviceProperties.setSendRenew(false);
return serviceProperties;
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider() throws UnknownHostException {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider
.setAuthenticationUserDetailsService(casUsuariDetailsService);
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider
.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey("an_id_for_this_auth_provider_only");
return casAuthenticationProvider;
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator(casProperties.getReturnUrl());
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter
.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setFilterProcessesUrl("/cas/login");
casAuthenticationFilter.setSessionAuthenticationStrategy(sessionControlAuthenticationStrategy());
return casAuthenticationFilter;
}
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() throws UnknownHostException {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(casProperties.getLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
@Bean
public ConcurrentSessionControlAuthenticationStrategy sessionControlAuthenticationStrategy() {
ConcurrentSessionControlAuthenticationStrategy csas = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
csas.setMaximumSessions(1);
csas.setExceptionIfMaximumExceeded(true);
return csas;
}
/*
* User impersonation
*/
@Bean
public SwitchUserFilter switchUserFilter() {
SwitchUserFilter filter = new SwitchUserFilter();
filter.setUserDetailsService(usuariDetailsService);
filter.setSwitchUserUrl("/login/impersonate");
filter.setExitUserUrl("/logout/impersonate");
filter.setTargetUrl("/");
filter.setUsernameParameter("username");
filter.setSwitchFailureUrl("/");
return filter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(casAuthenticationProvider());
}
@Bean
public Filter ajaxTimeOutRedirectFilter() {
AjaxTimeoutRedirectFilter f = new AjaxTimeoutRedirectFilter();
f.setCustomSessionExpiredErrorCode(HttpStatus.UNAUTHORIZED.value());
return f;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// Afegim el filtre del cas a les peticions
http.addFilter(casAuthenticationFilter());
http
.regexMatcher(WEB)
.exceptionHandling().authenticationEntryPoint(
casAuthenticationEntryPoint())
.and()
.addFilterAfter(ajaxTimeOutRedirectFilter(), ExceptionTranslationFilter.class)
;
http
.regexMatcher(WEB)
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.regexMatcher(WEB)
.authorizeRequests()
.antMatchers("/images/**", "/css/**", "/fonts/**", "/js/**", "/bower_components/**").permitAll()
.antMatchers("/logout").permitAll()
.antMatchers("/cas/login").permitAll()
.antMatchers("/login/impersonate").hasRole("ADMIN")
// Actuator
.antMatchers("/health").permitAll()
.antMatchers("/info").permitAll()
.antMatchers("/actuator").permitAll()
// Swagger
.antMatchers("/swagger-resources/**",
"/v2/api-docs", "/webjars/**", "/swagger-ui.html").permitAll()
// Resta
.regexMatchers(WEB).authenticated()
;
http
.regexMatcher(WEB)
.logout().logoutUrl("/logout").deleteCookies("JSESSIONID")
.logoutSuccessUrl(getUrlWithHostName(casProperties.getLogoutUrl()))
.invalidateHttpSession(true);
http
.regexMatcher(WEB)
.headers().frameOptions().sameOrigin();
}
private String getUrlWithHostName(String urlToFormat) throws UnknownHostException {
return MessageFormat.format(urlToFormat, InetAddress
.getLocalHost().getCanonicalHostName());
}
}
}
我已经尝试了很多,但似乎注册表总是空的,主体和会话总是返回一个空映射...
有什么建议吗?
谢谢
ConcurrentSessionAuthenticationStrategy 似乎还需要 RegisterSessionAuthenticationStrategy,如 Cyril Gabis 的回答所述:。以下对我有用:
@Bean
public SessionAuthenticationStrategy sessionAuthenticationStrategy() {
List<SessionAuthenticationStrategy> strategies = new ArrayList<>();
ConcurrentSessionControlAuthenticationStrategy concurrentStrategy =
new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
concurrentStrategy.setMaximumSessions(1);
concurrentStrategy.setExceptionIfMaximumExceeded(true);
RegisterSessionAuthenticationStrategy registerStrategy =
new RegisterSessionAuthenticationStrategy(sessionRegistry());
strategies.add(concurrentStrategy);
strategies.add(registerStrategy);
return new CompositeSessionAuthenticationStrategy(strategies);
}
总结:
- 创建 SessionRegistry bean
- 创建 SessionAuthenticationStrategy bean
- 使用 CasAuthenticationFilter(或使用 SAML 时,SAMLProcessingFilter)注册 SessionAuthenticationStrategy bean。
SessionRegistry bean:
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
正在使用 CasAuthenticationFilter 注册它:
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
return casAuthenticationFilter;
}
我正在使用 Spring Boot 2.1。6.RELEASE。
我需要使角色已更改的用户的会话过期。
我试图使用 sessionRegistry 但它不起作用,我不明白为什么...
这是我的 SecurityConfigurer class:
/**
* Configuració de seguretat
*/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
public static final String WEB = "\/((?!api).*)";
public static final String API = "/api/**";
@Order(1)
@Configuration
public static class RestApiWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Resource(name = "restAuthenticationFilter")
private Filter restAuthenticationFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher(API)
.csrf().disable()
.antMatcher(API)
.addFilterBefore(restAuthenticationFilter, CsrfFilter.class)
.antMatcher(API)
.authorizeRequests()
.antMatchers(API).authenticated()
.and()
.antMatcher(API)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
}
}
@Order(2)
@Configuration
public static class ApplicacionWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
private final CasProperties casProperties;
private final AuthenticationUserDetailsService<CasAssertionAuthenticationToken> casUsuariDetailsService;
private final UserDetailsService usuariDetailsService;
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}
@Autowired
public ApplicacionWebSecurityConfigurerAdapter(
CasProperties casProperties,
AuthenticationUserDetailsService<CasAssertionAuthenticationToken> casUsuariDetailsService,
@Qualifier("casUserDetailsService")
UserDetailsService usuariDetailsService) {
this.casProperties = casProperties;
this.casUsuariDetailsService = casUsuariDetailsService;
this.usuariDetailsService = usuariDetailsService;
}
@Bean
public ServiceProperties serviceProperties() throws UnknownHostException {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(getUrlWithHostName(casProperties.getValidateUrl()));
serviceProperties.setSendRenew(false);
return serviceProperties;
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider() throws UnknownHostException {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider
.setAuthenticationUserDetailsService(casUsuariDetailsService);
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider
.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey("an_id_for_this_auth_provider_only");
return casAuthenticationProvider;
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator(casProperties.getReturnUrl());
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter
.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setFilterProcessesUrl("/cas/login");
casAuthenticationFilter.setSessionAuthenticationStrategy(sessionControlAuthenticationStrategy());
return casAuthenticationFilter;
}
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() throws UnknownHostException {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(casProperties.getLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
@Bean
public ConcurrentSessionControlAuthenticationStrategy sessionControlAuthenticationStrategy() {
ConcurrentSessionControlAuthenticationStrategy csas = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
csas.setMaximumSessions(1);
csas.setExceptionIfMaximumExceeded(true);
return csas;
}
/*
* User impersonation
*/
@Bean
public SwitchUserFilter switchUserFilter() {
SwitchUserFilter filter = new SwitchUserFilter();
filter.setUserDetailsService(usuariDetailsService);
filter.setSwitchUserUrl("/login/impersonate");
filter.setExitUserUrl("/logout/impersonate");
filter.setTargetUrl("/");
filter.setUsernameParameter("username");
filter.setSwitchFailureUrl("/");
return filter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(casAuthenticationProvider());
}
@Bean
public Filter ajaxTimeOutRedirectFilter() {
AjaxTimeoutRedirectFilter f = new AjaxTimeoutRedirectFilter();
f.setCustomSessionExpiredErrorCode(HttpStatus.UNAUTHORIZED.value());
return f;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// Afegim el filtre del cas a les peticions
http.addFilter(casAuthenticationFilter());
http
.regexMatcher(WEB)
.exceptionHandling().authenticationEntryPoint(
casAuthenticationEntryPoint())
.and()
.addFilterAfter(ajaxTimeOutRedirectFilter(), ExceptionTranslationFilter.class)
;
http
.regexMatcher(WEB)
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.regexMatcher(WEB)
.authorizeRequests()
.antMatchers("/images/**", "/css/**", "/fonts/**", "/js/**", "/bower_components/**").permitAll()
.antMatchers("/logout").permitAll()
.antMatchers("/cas/login").permitAll()
.antMatchers("/login/impersonate").hasRole("ADMIN")
// Actuator
.antMatchers("/health").permitAll()
.antMatchers("/info").permitAll()
.antMatchers("/actuator").permitAll()
// Swagger
.antMatchers("/swagger-resources/**",
"/v2/api-docs", "/webjars/**", "/swagger-ui.html").permitAll()
// Resta
.regexMatchers(WEB).authenticated()
;
http
.regexMatcher(WEB)
.logout().logoutUrl("/logout").deleteCookies("JSESSIONID")
.logoutSuccessUrl(getUrlWithHostName(casProperties.getLogoutUrl()))
.invalidateHttpSession(true);
http
.regexMatcher(WEB)
.headers().frameOptions().sameOrigin();
}
private String getUrlWithHostName(String urlToFormat) throws UnknownHostException {
return MessageFormat.format(urlToFormat, InetAddress
.getLocalHost().getCanonicalHostName());
}
}
}
我已经尝试了很多,但似乎注册表总是空的,主体和会话总是返回一个空映射...
有什么建议吗? 谢谢
ConcurrentSessionAuthenticationStrategy 似乎还需要 RegisterSessionAuthenticationStrategy,如 Cyril Gabis 的回答所述:
@Bean
public SessionAuthenticationStrategy sessionAuthenticationStrategy() {
List<SessionAuthenticationStrategy> strategies = new ArrayList<>();
ConcurrentSessionControlAuthenticationStrategy concurrentStrategy =
new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
concurrentStrategy.setMaximumSessions(1);
concurrentStrategy.setExceptionIfMaximumExceeded(true);
RegisterSessionAuthenticationStrategy registerStrategy =
new RegisterSessionAuthenticationStrategy(sessionRegistry());
strategies.add(concurrentStrategy);
strategies.add(registerStrategy);
return new CompositeSessionAuthenticationStrategy(strategies);
}
总结:
- 创建 SessionRegistry bean
- 创建 SessionAuthenticationStrategy bean
- 使用 CasAuthenticationFilter(或使用 SAML 时,SAMLProcessingFilter)注册 SessionAuthenticationStrategy bean。
SessionRegistry bean:
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
正在使用 CasAuthenticationFilter 注册它:
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
return casAuthenticationFilter;
}