飞道的博客

Spring Security 自定义登录Session配置

506人阅读  评论(0)
适用于session方式的登录,不适用于jwt token方式的登录。因为jwt token方式的话session就没什么事儿了 (此处为了防止小白不懂原理盲目抄)。

有这样一个需求,一个账号只能在一个客户端浏览器上登录,如果同样的账号在别的客户端浏览器上登录的话,之前的登录需要被踢下去。这个需求看似很简单,而且默认情况下使用Spring Security配置也挺简单,如下配置即可:


   
  1. @Override
  2. protected void configure (HttpSecurity http) throws Exception {
  3. http
  4. ... //此处忽略若干行配置
  5. .sessionManagement()
  6. .maximumSessions( 1);
  7. }

这个配置在默认formLogin状态下生效,但如果使用自定义过滤器接管登录过程的话就会失效,如这样:


   
  1. @Override
  2. protected void configure (HttpSecurity http) throws Exception {
  3. http
  4. ... //此处忽略若干行配置
  5.     // 添加自己的登录过滤器
  6.     .addFilterBefore(adminLoginFilter(), UsernamePasswordAuthenticationFilter.class)
  7.     // 因为adminLoginFilter接管了默认formLogin的工作,所以下面的session配置失效了
  8. .sessionManagement()
  9. .maximumSessions( 1);
  10. }

这时我们需要手动配置session了,先看看官网是怎么说的 官网说明 这是官网的一段话

If you are using a customized authentication filter for form-based login, then you have to configure concurrent session control support explicitly.

官网也提供了具体配置方法


   
  1. <http>
  2. <custom-filter position= "CONCURRENT_SESSION_FILTER" ref= "concurrencyFilter" />
  3. <custom-filter position= "FORM_LOGIN_FILTER" ref= "myAuthFilter" />
  4. <session-management session-authentication-strategy-ref= "sas"/>
  5. </http>
  6. <beans:bean id= "redirectSessionInformationExpiredStrategy"
  7. class= "org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy">
  8. <beans:constructor-arg name= "invalidSessionUrl" value= "/session-expired.htm" />
  9. </beans:bean>
  10. <beans:bean id= "concurrencyFilter"
  11. class= "org.springframework.security.web.session.ConcurrentSessionFilter">
  12. <beans:constructor-arg name= "sessionRegistry" ref= "sessionRegistry" />
  13. <beans:constructor-arg name= "sessionInformationExpiredStrategy" ref= "redirectSessionInformationExpiredStrategy" />
  14. </beans:bean>
  15. <beans:bean id= "myAuthFilter" class=
  16. "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
  17. <beans:property name= "sessionAuthenticationStrategy" ref= "sas" />
  18. <beans:property name= "authenticationManager" ref= "authenticationManager" />
  19. </beans:bean>
  20. <beans:bean id= "sas" class= "org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
  21. <beans:constructor-arg>
  22. <beans:list>
  23. <beans:bean class= "org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
  24. <beans:constructor-arg ref= "sessionRegistry"/>
  25. <beans:property name= "maximumSessions" value= "1" />
  26. <beans:property name= "exceptionIfMaximumExceeded" value= "true" />
  27. </beans:bean>
  28. <beans:bean class= "org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
  29. </beans:bean>
  30. <beans:bean class= "org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
  31. <beans:constructor-arg ref= "sessionRegistry"/>
  32. </beans:bean>
  33. </beans:list>
  34. </beans:constructor-arg>
  35. </beans:bean>
  36. <beans:bean id= "sessionRegistry"
  37. class= "org.springframework.security.core.session.SessionRegistryImpl" />

官网提供的是xml配置方法,现在应该是比较少用了,所以我们得在自己项目中使用代码配置,具体流程:

第一步 定义一个sessionRegistry bean


   
  1. @Bean
  2. public SessionRegistry sessionRegistry (){
  3. return new SessionRegistryImpl();
  4. }

第二步 定义几个Session Strategy bean,其中在ConcurrentSessionControlAuthenticationStrategy配置账号的最大同时登录数


   
  1. @Bean
  2. public ConcurrentSessionControlAuthenticationStrategy controlAuthenticationStrategy (SessionRegistry sessionRegistry){
  3. ConcurrentSessionControlAuthenticationStrategy strategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
  4. strategy.setMaximumSessions( 1); // 这里配置一个账号最大登录数
  5. return strategy;
  6. }
  7. @Bean
  8. public SessionFixationProtectionStrategy sessionFixationProtectionStrategy (){
  9. return new SessionFixationProtectionStrategy();
  10. }
  11. @Bean
  12. public RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy (SessionRegistry sessionRegistry){
  13. return new RegisterSessionAuthenticationStrategy(sessionRegistry);
  14. }

第三步 定义CompositeSessionAuthenticationStrategy bean,他接受的是List集合,也就是其他Session Strategy的集合


   
  1. @Bean
  2. public CompositeSessionAuthenticationStrategy sessionAuthenticationStrategy (List<SessionAuthenticationStrategy> authenticationStrategies){
  3. return new CompositeSessionAuthenticationStrategy(authenticationStrategies);
  4. }

第四步 定义ConcurrentSessionFilter bean


   
  1. @Bean
  2. public ConcurrentSessionFilter concurrentSessionFilter (SessionRegistry sessionRegistry){
  3. return new ConcurrentSessionFilter(sessionRegistry);
  4. }

第五步 在自己的自定义登录filter里面设置session strategy


   
  1. public AdminLoginFilter adminLoginFilter (CompositeSessionAuthenticationStrategy strategy) throws Exception {
  2. AdminLoginFilter adminLoginFilter = new AdminLoginFilter();
  3. ... 省略若干行配置
  4. adminLoginFilter.setSessionAuthenticationStrategy(strategy);
  5. return adminLoginFilter;
  6. }

第六步 在configure(HttpSecurity http)里面配置session


   
  1. @Override
  2. protected void configure (HttpSecurity http) throws Exception {
  3. List<SessionAuthenticationStrategy> authenticationStrategies = Arrays.asList(
  4. controlAuthenticationStrategy(sessionRegistry()),
  5. sessionFixationProtectionStrategy(),
  6. registerSessionAuthenticationStrategy(sessionRegistry())
  7. );
  8. http
  9. ... //此处忽略若干行配置
  10. .addFilterBefore(concurrentSessionFilter(sessionRegistry()),ConcurrentSessionFilter.class)
  11. .addFilterBefore(adminLoginFilter(sessionAuthenticationStrategy(authenticationStrategies)), UsernamePasswordAuthenticationFilter.class)
  12. .sessionManagement()
  13. .sessionAuthenticationStrategy(sessionAuthenticationStrategy(authenticationStrategies));
  14. }

下面看完整的代码


   
  1. @Configuration
  2. @EnableWebSecurity
  3. @EnableGlobalMethodSecurity(prePostEnabled = true)
  4. public class PortalSecurityConfig2 extends WebSecurityConfigurerAdapter {
  5. @Autowired
  6. private AdminLoginService adminDetailsService;
  7. @Bean
  8. public PasswordEncoder passwordEncoder () {
  9. return new BCryptPasswordEncoder();
  10. }
  11. public AdminLoginFilter adminLoginFilter (CompositeSessionAuthenticationStrategy strategy) throws Exception {
  12. AdminLoginFilter adminLoginFilter = new AdminLoginFilter();
  13. adminLoginFilter.setFilterProcessesUrl( "/admin/login");
  14. adminLoginFilter.setAuthenticationManager(authenticationManagerBean());
  15. adminLoginFilter.setSessionAuthenticationStrategy(strategy);
  16. return adminLoginFilter;
  17. }
  18. @Override
  19. protected void configure (HttpSecurity http) throws Exception {
  20. List<SessionAuthenticationStrategy> authenticationStrategies = Arrays.asList(
  21. controlAuthenticationStrategy(sessionRegistry()),
  22. sessionFixationProtectionStrategy(),
  23. registerSessionAuthenticationStrategy(sessionRegistry())
  24. );
  25. http
  26. .authorizeRequests().anyRequest().authenticated()
  27. .and()
  28. .addFilterBefore(concurrentSessionFilter(sessionRegistry()), ConcurrentSessionFilter.class)
  29. .addFilterBefore(adminLoginFilter(sessionAuthenticationStrategy(authenticationStrategies)), UsernamePasswordAuthenticationFilter.class)
  30. .sessionManagement()
  31. .sessionAuthenticationStrategy(sessionAuthenticationStrategy(authenticationStrategies));
  32. }
  33. @Override
  34. protected void configure (final AuthenticationManagerBuilder auth) throws Exception {
  35. auth.userDetailsService(adminDetailsService);
  36. }
  37. @Bean
  38. public SessionRegistry sessionRegistry (){
  39. return new SessionRegistryImpl();
  40. }
  41. @Bean
  42. public ConcurrentSessionFilter concurrentSessionFilter (SessionRegistry sessionRegistry){
  43. return new ConcurrentSessionFilter(sessionRegistry);
  44. }
  45. @Bean
  46. public ConcurrentSessionControlAuthenticationStrategy controlAuthenticationStrategy (SessionRegistry sessionRegistry){
  47. ConcurrentSessionControlAuthenticationStrategy strategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
  48. strategy.setMaximumSessions( 1);
  49. return strategy;
  50. }
  51. @Bean
  52. public SessionFixationProtectionStrategy sessionFixationProtectionStrategy (){
  53. return new SessionFixationProtectionStrategy();
  54. }
  55. @Bean
  56. public RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy (SessionRegistry sessionRegistry){
  57. return new RegisterSessionAuthenticationStrategy(sessionRegistry);
  58. }
  59. @Bean
  60. public CompositeSessionAuthenticationStrategy sessionAuthenticationStrategy (List<SessionAuthenticationStrategy> authenticationStrategies){
  61. return new CompositeSessionAuthenticationStrategy(authenticationStrategies);
  62. }
  63. }

希望以上内容能帮到你。


转载:https://blog.csdn.net/u011492260/article/details/129099028
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场