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
原创粉丝点击