SpringBoot集成SpringSecurity ------Session管理

SpringBoot集成SpringSecurity ------Session管理

Scroll Down

用户登录成功后,信息保存在服务器Session中,接下来是对Session的处理。

Session超时设置

Session超时时间,也就是用户登录期的有效时间,配置如下:

server.servlet.session.timeout= 60

单位为秒。为了测试方便,将Session的有效期为60秒。

值得注意的是,Session的最小有效期为60秒,也就是说即使你设置为小于60秒的值,其有效期还是为60秒。

Session失效后,刷新页面或者继续操作,将会跳转到登录页面,可以添加配置,自定义Session失效后的行为操作。
在Security配置中配置Session管理器,并配置Session失效后要跳转的URL:


   @Override
    protected void configure(HttpSecurity http) throws Exception {
        //开启登录配置
        http.authorizeRequests()
                //请求不需要验证
                    .antMatchers("/code/image").permitAll()
                    .antMatchers("/code/sms").permitAll()
                    .antMatchers("/session/invalid").permitAll()
                //其余所有请求需要验证
                    .anyRequest()
                    .authenticated()
                .and()
                // 添加验证码校验过滤器
                    .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
                    .addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class)
                //设置登录认证界面
                    .formLogin().loginPage("/login")
                //登录成功后的处理接口
                    .loginProcessingUrl("/login")
//                //自定义登录用户名和密码属性,默认为username,password
                    .usernameParameter("username").passwordParameter("password")
                //登录成功后的处理器
                    .successHandler(customAuthenticationSuccessHandler)
                //配置登录失败的回溯
                    .failureHandler(customAuthenticationFailureHandler)
                    .permitAll()//和表单登录相关的接口统统都直接通过
                .and()
                    .logout().logoutUrl("/logout")
                // 配置注销成功的回调
                    .logoutSuccessHandler(customLogoutHandler) .deleteCookies("JSESSIONID")
                    .permitAll()
                .and()
                    .httpBasic()
                .and()
                //Session管理
                // Session超时
                    .sessionManagement().invalidSessionUrl("/session/invalid")
                .and()
                // 关闭CSRF跨域
                    .csrf().disable()
                // 将短信验证码认证配置加到 Spring Security 中
                .apply(smsAuthenticationConfig);
    }

上面配置了Session失效后跳转到/session/invalid,并且将这个URL添加到了免认证路径中。
在Controller中添加方法,映射路径: /session/invalid

@GetMapping("session/invalid")
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public String sessionInvalid(){
    return "session已失效,请重新认证";
}

44.png

Session并发控制

Session并发控制可以控制一个账号同事最多能登陆多少个,在Sesuciry中配置Session相关的配置:

    @Autowired
    CustomSessionExpiredStrategy sessionExpiredStrategy;

.and()
   //Session管理
   // Session超时
   .sessionManagement().invalidSessionUrl("/session/invalid")
   // 指定最大登录数
   .maximumSessions(1)
   // 当达到最大值时,是否保留已经登录的用户;true:新用户无法登录;false:旧用户被踢出
    .maxSessionsPreventsLogin(false)
    .expiredSessionStrategy(sessionExpiredStrategy)
 .and()

其中 CustomSessionExpiredStrategy 实现 SessionInformationExpiredStrategy:

@Component
public class MySessionExpiredStrategy implements SessionInformationExpiredStrategy {

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
        HttpServletResponse response = event.getResponse();
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write("您的账号已经在别的地方登录,当前登录已失效。如果密码遭到泄露,请立即修改密码!");
    }
}

演示界面:
YBFH1A9M_V459H8`XLEN.png

Session集群处理

当我们登录成功后,用户认证的信息存储在Session中,而这些Session默认是存储在运行运用的服务器上的,比如Tomcat,netty等。当应用集群部署的时候,用户在A应用上登录认证了,后续通过负载均衡可能会把请求发送到B应用,而B应用服务器上并没有与该请求匹配的认证Session信息,所以用户就需要重新进行认证。要解决这个问题,我们可以把Session信息存储在第三方容器里(如Redis集群),而不是各自的服务器,这样应用集群就可以通过第三方容器来共享Session了。
引入Redis和Spring Session依赖:


 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

然后在yml中配置Session存储方式为Redis:


## session
server.servlet.session.timeout= 60
spring.session.store-type= redis

### redis
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0