Spring Security -- session管理(转载)
用户登录成功后,信息保存在服务器的session中,并返回给用户一个sessionid,sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,当用户再次请求时,将携带该sessionId,如果在服务器中能够找到该sessionid,则表示用户登录成功。这节将会学习如何管理session。这节将会在Spring Security -- 添加图形验证码(转载)的基础上继续扩展。
一、session超时设置
1、配置session
session超时时间也就是用户登录的有效时间。要设置session超时时间很简单,只需要在配置文件application.yml中添加:
#session设置超时
server:
servlet:
session:
timeout: 3600
单位为秒,通过上面的配置,session的有效期为一个小时。值得注意的是,session的最小有效期为60秒,也就是说即使你设置为小于60秒的值,其有效期还是为60秒。
session失效后,刷新页面后将跳转到认证页面,我们可以再添加一些配置,自定义session失效后的一些行为。在Spring Security中配置session管理器,并配置session失效后要跳转的URL:
@Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加图片验证码校验过滤器 .addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加手机短信验证码校验过滤器 .authorizeRequests() // 授权配置 .antMatchers("/code/image","/code/sms","/session/invalid") .permitAll() // 无需认证的请求路径 .anyRequest() // 任何请求 .authenticated() //都需要身份认证 .and() .formLogin() // 或者httpBasic() .loginPage("/login") // 指定登录页的路径 //我们的form表单action是将请求提交到/login/mobile页面,而在Spring Security中配置的 .loginProcessingUrl("/login") 值为/login,这两者为什么不一样呢?这样做的目的是通过指定Spring Security中的UsernamePasswordAuthenticationFilter的拦截目标为post请求/login,从而使得该过滤器不会拦截/login/mobile请求;那么针对/login/mobile请求我们会仿照UsernamePasswordAuthenticationFilter定义自己的过滤器,然后对其进行认证; .loginProcessingUrl("/login") // 指定自定义form表单提交请求的路径 .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 // 必须允许所有用户访问我们的登录页(例如未验证的用户,否则验证流程就会进入死循环) // 这个formLogin().permitAll()方法允许所有用户基于表单登录访问/login这个page。 .permitAll() // .and() // .rememberMe() // .tokenRepository(persistentTokenRepository) // 配置 token 持久化仓库 // .tokenValiditySeconds(3600) // remember 过期时间,单为秒 // .userDetailsService(userDetailsService) // 处理自动登录逻辑 // .and() // .logout() // .permitAll() .and() .sessionManagement() //添加session管理器 .invalidSessionUrl("/session/invalid") //Session失效后跳转到这个链接 .and() //默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉 .csrf().disable() .apply(smsAuthenticationConfig); // 将短信验证码认证配置加到 Spring Security 中 添加一个安全配置其到http的configurers集合 }
2、SessionController
上面配置了session失效后跳转到/session/invalid,并且将这个URL添加到了免认证路径中。
在包com.zy.example.conmtroller下创建类SessionController,添加一个方法,映射该请求:
package com.zy.example.controller; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; /** * @Author: zy * @Description: session路由 * @Date: 2020/2/16 */ public class SessionController { @GetMapping("/session/invalid") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String sessionInvalid(){ return "session已失效,请重新认证"; } }
3、测试
为了演示,我们将session的超时时间设置为最小值60秒,重启项目,访问http://127.0.0.1:8080/index,并成功认证后输出:
等待60秒并刷新页面:
可看到请求跳转到了我们自定义的/session/invalidURL上。
4、session并发控制
session并发控制可以控制一个账号同一时刻最多能登录多少个。我们在Spring Security配置中继续添加session相关配置:
@Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加图片验证码校验过滤器 .addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加手机短信验证码校验过滤器 .authorizeRequests() // 授权配置 .antMatchers("/code/image","/code/sms","/session/invalid") .permitAll() // 无需认证的请求路径 .anyRequest() // 任何请求 .authenticated() //都需要身份认证 .and() .formLogin() // 或者httpBasic() .loginPage("/login") // 指定登录页的路径 //我们的form表单action是将请求提交到/login/mobile页面,而在Spring Security中配置的 .loginProcessingUrl("/login") 值为/login,这两者为什么不一样呢?这样做的目的是通过指定Spring Security中的UsernamePasswordAuthenticationFilter的拦截目标为post请求/login,从而使得该过滤器不会拦截/login/mobile请求;那么针对/login/mobile请求我们会仿照UsernamePasswordAuthenticationFilter定义自己的过滤器,然后对其进行认证; .loginProcessingUrl("/login") // 指定自定义form表单提交请求的路径 .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 // 必须允许所有用户访问我们的登录页(例如未验证的用户,否则验证流程就会进入死循环) // 这个formLogin().permitAll()方法允许所有用户基于表单登录访问/login这个page。 .permitAll() // .and() // .rememberMe() // .tokenRepository(persistentTokenRepository) // 配置 token 持久化仓库 // .tokenValiditySeconds(3600) // remember 过期时间,单为秒 // .userDetailsService(userDetailsService) // 处理自动登录逻辑 // .and() // .logout() // .permitAll() .and() //默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉 .csrf().disable() .apply(smsAuthenticationConfig) // 将短信验证码认证配置加到 Spring Security 中 添加一个安全配置其到http的configurers集合 .and() .sessionManagement() //添加session管理器 .invalidSessionUrl("/session/invalid") //Session失效后跳转到这个链接 .maximumSessions(1) .expiredSessionStrategy(sessionInformationExpiredStrategy); }
maximumSessions配置了最大session并发数量为1个,如果admin这个账户登录后,在另一个客户端也使用admin账户登录,那么第一个使用admin登录的账户将会失效,类似于一个先入先出队列。sessionInformationExpiredStrategy配置了session在并发下失效后的处理策略,这里为我们在com.zy.example.config包下自定义策略CustomSessionInformationExpiredStrategy :
package com.zy.example.config; import org.springframework.http.HttpStatus; import org.springframework.security.web.session.SessionInformationExpiredEvent; import org.springframework.security.web.session.SessionInformationExpiredStrategy; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @Author: zy * @Description: 配置了Session在并发下失效后的处理策略 * @Date: 2020/2/16 */ @Component public class CustomSessionInformationExpiredStrategy 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("您的账号已经在别的地方登录,当前登录已失效。如果密码遭到泄露,请立即修改密码!"); } }
为了演示这个效果,我们先将session超时时间设置久一点,比如3600秒,然后重启项目,在Chrome里使用admin账户登录。
登录成功后,在IE上也是用admin账户登录,登录成功后回到Chrome,刷新页面,效果如下所示:
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步