spring security(八) session 并发,剔除前一个用户
来源:互联网 发布:淘宝店铺首页图片设置? 编辑:程序博客网 时间:2024/05/16 15:20
解决 session 并发问题 ,同时只有一个用户在线。 有一个用户在线后其他的设备登录此用户将剔除前一个用户。强制前一个用户下线。
本文代码,是基于 springboot+security restful权限控制官方推荐(五)的代码
1.修改security配置
添加 SessionRegistry,自己管理SessionRegistry。
@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(securedEnabled = true)public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserService customUserService; @Autowired SessionRegistry sessionRegistry; @Autowired protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customUserService).passwordEncoder(new BCryptPasswordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers("/users/**") .authenticated() .antMatchers(HttpMethod.POST) .authenticated() .antMatchers(HttpMethod.PUT) .authenticated() .antMatchers(HttpMethod.DELETE) .authenticated() .antMatchers("/**") .permitAll() .and() .sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry); http.httpBasic(); } @Bean public SessionRegistry getSessionRegistry(){ SessionRegistry sessionRegistry=new SessionRegistryImpl(); return sessionRegistry; }
2.LoginController
修改登录,登录成功后清除前一个在线用户(dropPreviousUser 清除前一个用户)
@RequestMapping(value = "/login") @ResponseBody //用户名密码是用base64 加密 原文为 admin:admin 即 用户名:密码 内容是放在request.getHeader 的 "authorization" 中 public Object login(@AuthenticationPrincipal SysUser loginedUser, @RequestParam(name = "logout", required = false) String logout,HttpServletRequest request) { if (logout != null) { return "logout"; } if (loginedUser != null) { SessionUtil.dropPreviousUser(request,sessionRegistry,loginedUser); return loginedUser; } return null; }
3.SessionUtil
session 管理工具类
/** * Created by yangyibo on 8/23/17. */public class SessionUtil { /** * 辨别用户是否已经登录 * * @param request * @param sessionRegistry * @param loginedUser */ public static void deleteSameUser(HttpServletRequest request, SessionRegistry sessionRegistry, User loginedUser) { SecurityContext sc = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT"); List<SessionInformation> sessionsInfo; sessionsInfo = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), true); String currentSessionId; if (null != sessionsInfo && sessionsInfo.size() == 0) { sessionRegistry.registerNewSession(request.getSession().getId(), sc.getAuthentication().getPrincipal()); sessionsInfo = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), false); } currentSessionId = sessionsInfo.get(0).getSessionId(); List<Object> o = sessionRegistry.getAllPrincipals(); for (Object principal : o) { if (principal instanceof User && (loginedUser.getUsername().equals(((User) principal).getUsername()))) { List<SessionInformation> oldSessionsInfo = sessionRegistry.getAllSessions(principal, false); if (null != oldSessionsInfo && oldSessionsInfo.size() > 0 && !oldSessionsInfo.get(0).getSessionId().equals(currentSessionId)) { for (SessionInformation sessionInformation : sessionsInfo) { //当前session失效 sessionInformation.expireNow(); sc.setAuthentication(null); sessionRegistry.removeSessionInformation(currentSessionId); throw new GeneralServerExistException(ErrorMessage.ALONG_LOGIN_ERROTR.toString()); } } } } } /** * 剔除前一个用户 * * @param request * @param sessionRegistry * @param loginedUser */ public static void dropPreviousUser(HttpServletRequest request, SessionRegistry sessionRegistry, User loginedUser, SysMessageService sysMessageService) { SecurityContext sc = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT"); List<SessionInformation> sessionsInfo; sessionsInfo = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), false); if (sessionsInfo.size() > 0) { String currentSessionId = sessionsInfo.get(0).getSessionId(); List<Object> o = sessionRegistry.getAllPrincipals(); for (Object principal : o) { if (principal instanceof User && (loginedUser.getUsername().equals(((User) principal).getUsername()))) { List<SessionInformation> oldSessionsInfo = sessionRegistry.getAllSessions(principal, false); if (null != oldSessionsInfo && oldSessionsInfo.size() > 0 && !oldSessionsInfo.get(0).getSessionId().equals(currentSessionId)) { for (SessionInformation sessionInformation : oldSessionsInfo) { //当前session失效 //send message sysMessageService.sendMessage(((User) principal).getUsername(), new SysMessage(null, Consts.NOTIFICATION_TYPE_HADLOGIN_CONTENT, 5, Consts.NOTIFICATION_ACCEPT_TYPE_HADLOGIN)); sessionInformation.expireNow(); } } } } }else { throw new GeneralServerExistException(ErrorMessage.ALONG_LOGIN_ERROTR.toString()); } } /** * session 失效 * * @param request * @param sessionRegistry */ public static void expireSession(HttpServletRequest request, User user, SessionRegistry sessionRegistry) { List<SessionInformation> sessionsInfo = null; if (null != user) { List<Object> o = sessionRegistry.getAllPrincipals(); for (Object principal : o) { if (principal instanceof User && (user.getUsername().equals(((User) principal).getUsername()))) { sessionsInfo = sessionRegistry.getAllSessions(principal, false); } } } else if (null != request) { SecurityContext sc = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT"); if (null != sc.getAuthentication().getPrincipal()) { sessionsInfo = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), false); sc.setAuthentication(null); } } if (null != sessionsInfo && sessionsInfo.size() > 0) { for (SessionInformation sessionInformation : sessionsInfo) { //当前session失效 sessionInformation.expireNow(); sessionRegistry.removeSessionInformation(sessionInformation.getSessionId()); } } }}
4.session 失效
制定定时任务,定时使session 失效。失效机制,定时扫描在线用户,判断在线用户的最后一次操作时间AccessLastTime 于当前的时间差是否超过 session失效时间 ,如果超过session 失效时间,将session 置为失效。
此处的session失效和 springboot 配置文件里配置的session 失效时间应当一致。(springboot 配置文件里配置的session 失效实际上并不能将我门自己管理的SessionRegistry 中的session失效。)
/** * 超时事件检查 */ @Scheduled(cron = "0 0/1 * * * ?") public void ScanUserOnline() { //获取所有在线用户 List<User> users = userDao.getUsersWithOnLine(4); users.stream().parallel().forEach(user -> { //通过时间判断是否session过期 if (CommonUtil.CalculationData(user.getAccessLastTime(),30)) { //如果过期则设置用户为下下线状态 updateOnline(user.getId(),4,null); //session 置为失效 SessionUtil.expireSession(null,user,sessionRegistry); } }); }
本文源码:https://github.com/527515025/springBoot
阅读全文
0 0
- spring security(八) session 并发,剔除前一个用户
- spring security(七) session 并发,一个用户在线后其他的设备登录此用户失败
- Spring security实现指定用户session过期
- spring-security+spring-session配置
- Spring-security 锁定用户
- 剔除session
- spring security session expired issue
- 13. Spring Security session管理
- spring security 3.0 的 用户详细信息的 session 扩展 (基于rapid framework)
- Spring security获取当前用户
- Spring Security之匿名用户
- Spring security 和 Spring session 一起使用
- 7、Spring Session-Spring Security集成
- 学spring security前的知识回顾
- 解决Spring Security 开启remember-me(持久化),session并发控制后重启服务器remember-me持久化凭证消失问题
- spring-security与Hibernate-Session冲突
- Spring Security + SWFUpload and the session problem
- Spring Security http切换https session丢失
- 第九章 –– 常见类之Date、DateFormat和Calender
- Android 跳转到系统设置界面汇总
- Material Design整理(四)——DrawerLayout
- 如何将网易云音乐的歌单同步到spotify
- CUDA从入门到精通
- spring security(八) session 并发,剔除前一个用户
- CodeBlocks中统一改变某变量名方法
- 八、matplotlib系列---pyplot直方图的绘制
- 【转】Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier性能比较
- 放大镜
- BING: Binarized Normed Gradients for Objectness Estimation at 300fps
- 最近不知道干啥了,很迷茫,需要很大的勇气来做事
- 百度地图-marker 标 内容
- 系统第一次起来有交互信息