一个用户只能登录一次

仅仅思路,这是springsecurety的

package com.dbapp.fly.config.security;
 
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.dbapp.fly.entity.SysUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

//登录用户认证通过后,显示登录成功页面前,做的操作。
@Component
public class MyAuthenctiationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
 
	private static final Logger logger = LoggerFactory.getLogger(MyAuthenctiationSuccessHandler.class);
 
	// key为sessionId,value为HttpSession,使用static,定义静态变量,使之程序运行时,一直存在内存中。
	// 保存所有已经登录用户的会话(每个浏览器一个会话)
	public static HashMap<String, HttpSession> sessionMap = new HashMap<String, HttpSession>();
 
	@Autowired
	// @Qualifier("sessionRegistry")
	private SessionRegistry sessionRegistry;
 
	// @Bean(name="sessionRegistry",value="sessionRegistry")
	@Bean
	// @Bean(name="sessionRegistry")
	public SessionRegistry getSessionRegistry() {
		return new SessionRegistryImpl();
	}
 
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws ServletException, IOException {
 
		// 1.登录认证成功后,获取用户名
		//(只能在认证成功通过后,才能获得sc,不然在CustomUserService implements UserDetailsService的loadUserByUsername方法中是第二次才能获取到)
		SecurityContext sc = SecurityContextHolder.getContext();
		String currentuser = ((SysUser) sc.getAuthentication().getPrincipal()).getUserName();
		logger.info("当前登录用户:" + currentuser);
 
		
		// 2.先判断用户是否重复登录
		Iterator<Entry<String, HttpSession>> iterator = sessionMap.entrySet().iterator();
		while(iterator.hasNext()) {
			Map.Entry<String, HttpSession> entry = iterator.next();
			HttpSession session = entry.getValue();
			// 2.1 判断session中所包含的用户名称是否有当前登录用户
			String username = SessionUtil.getUserName(session);
			if (currentuser.equals(username)) {
				logger.info("用户:" + currentuser + "已经在其它地方登录过,将踢除!");
				SessionUtil.expireSession(session);
				logger.info("删除的会话:"+entry.getKey());
				// 2.2 从sessionMap中踢除会话
				iterator.remove();
				// 2.3 从sessionRegistry中踢除会话
				sessionRegistry.removeSessionInformation(session.getId());
			}
		}
		
		/*//以下这种方法会引起java.util.ConcurrentModificationException: null 错误,    HashMap
		// 2.先判断用户是否重复登录
		for (Entry<String, HttpSession> entry : sessionMap.entrySet()) {
			HttpSession session = entry.getValue();
			// 2.1 判断session中所包含的用户名称是否有当前登录用户
			String username = SessionUtil.getUserName(session);
			if (currentuser.equals(username)) {
				logger.info("用户:" + currentuser + "已经在其它地方登录过,将踢除!");
				SessionUtil.expireSession(session);
				logger.info(entry.getKey());
				sessionMap.remove(entry.getKey());//这里会引起同步错误
				sessionRegistry.removeSessionInformation(session.getId());
			}
		}*/
 
		// 3.将当前session保存到sessionMap中
		logger.info("将当前会话:" + request.getSession().getId() + ",保存到sessionMap");
		sessionMap.put(request.getSession().getId(), request.getSession());
		for (Entry<String, HttpSession> entry : sessionMap.entrySet()) {
			logger.info("显示已经保存的sessionMap:Key: " + entry.getKey() + " Value: " + entry.getValue());
		}
 
		// 4.打印所有认证通过的用户(包含重复登录的,不过上面已经踢除了)
		List<Object> principals = sessionRegistry.getAllPrincipals();
  		List<String> usersNamesList = new ArrayList<String>();
  		for (Object principal: principals) {
  		    if (principal instanceof SysUser) {
  		        usersNamesList.add(((SysUser) principal).getUserName());
  		    }
  		}
  		logger.info("已经认证通过的用户数:"+usersNamesList.size()+",     已经认证通过用户:"+usersNamesList.toString());
		
		
		// response.sendRedirect("/");
		super.onAuthenticationSuccess(request, response, authentication);
	}
 
}
package com.dbapp.fly.config.security;

import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//启动类加上注解@ServletComponentScan,这样才能扫描到监听器
//@WebListener
public class MySessionListner implements HttpSessionListener {

	private static final Logger logger = LoggerFactory.getLogger(MySessionListner.class);

	/**
	 * 新建session时(打开浏览器访问登录页面时,服务器会创建一个新的session)
	 */
	@Override
	public void sessionCreated(HttpSessionEvent httpSessionEvent) {
		System.out.println("创建session");

	}

	/**
	 * 删除session时(退出系统)
	 */
	@Override
	public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
		logger.info("销毁session时");
		MyAuthenctiationSuccessHandler.sessionMap.remove(httpSessionEvent.getSession().getId());
	}

}
package com.dbapp.fly.config.security;
 
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
@Configuration
public class MywebConfig implements WebMvcConfigurer {
    @Bean
    public ServletListenerRegistrationBean listenerRegist() {
        ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean();
        srb.setListener(new MySessionListner());
        System.out.println("listener");
        return srb;
    }
}
package com.dbapp.fly.config.security;
 
import java.util.Enumeration;
import java.util.List;
 
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import com.dbapp.fly.entity.SysUser;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.User;

 
public class SessionUtil {
 
	private static SecurityContext attribute;
	
	/**
	 * 根据当前session获取当前登录用户对象
	 * @param session
	 * @return guser
	 */
	public static SysUser getUser(HttpSession session) {
		try {
			attribute = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT");
			SysUser principal = (SysUser) attribute.getAuthentication().getPrincipal();
			return principal;
		} catch (Exception e) {
		}
		return null;
	}
	
	/**
	 * 根据当前session获取当前登录用户ID
	 * @param session
	 * @return guser
	 */
	public static Long getUserId(HttpSession session) {
		try {
			attribute = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT");
			SysUser principal = (SysUser) attribute.getAuthentication().getPrincipal();
			return principal.getId();
		} catch (Exception e) {
		}
		return null;
	}
	
	/**
	 * 根据session获取用户名称
	 * @param session
	 * @return void
	 */
	public static String getUserName(HttpSession session) {
		try {
			attribute = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT");
			SysUser principal = (SysUser) attribute.getAuthentication().getPrincipal();
			return principal.getUserName();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
}
	
	/**
	 * 根据session获取count
	 * session中包含一个count键默认为null,可以用来统计登录次数
	 * @param session
	 * @return void
	 */
	public static void count(HttpSession session) {
		ServletContext context = session.getServletContext();
		
		System.out.println("sessionid:"+session.getId()+",的count是:"+context.getAttribute("count"));
	}
	
	
    /**
     * 辨别用户是否已经登录,如果已经登录就不能登录了。
     *
     * @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 , SysMessageService sysMessageService
     */
    public static void expireSession(HttpSession session) {
    	session.invalidate();
    }
    
    
    /**
     * 剔除前一个用户
     *
     * @param request
     * @param sessionRegistry
     * @param loginedUser
     * @param , SysMessageService sysMessageService
     */
    public static void dropPreviousUser2(HttpServletRequest request, SessionRegistry sessionRegistry, SysUser loginedUser) {
    	List<SessionInformation> sessionsInfo = null;
    	//登录以后session里才会加入键名为"SPRING_SECURITY_CONTEXT"的字段
        SecurityContext sc = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
        
        if(sc!=null) {
        	System.out.println("!!!!!!!!!!!!"+sc.getAuthentication().getPrincipal().toString());
        	//获取当前登录用户的会话信息集合
        	sessionsInfo = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), false);
        	if (sessionsInfo.size() > 0) {
        		//当前会话ID
        		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);
        				//如果会话信息不为空且会话信息的ID不等于当前会话ID
        				if (null != oldSessionsInfo && oldSessionsInfo.size() > 0 && !oldSessionsInfo.get(0).getSessionId().equals(currentSessionId)) {
        					//遍历已经登录用户的会话信息,并设置过期,即删除session
        					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();
        					}
        				}
        			}
        		}
        	}
        }
        
    }
 
    /**
     * 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());
            }
        }
    }
    
    public void showsession(HttpServletRequest request) {
    	//获取session  
    	HttpSession   session   =   request.getSession();    
    	// 获取session中所有的键值  
    	Enumeration<String> attrs = session.getAttributeNames();  
    	// 遍历attrs中的
    	while(attrs.hasMoreElements()){
    	// 获取session键值  
    	    String name = attrs.nextElement().toString();
    	    // 根据键值取session中的值  
    	    Object vakue = session.getAttribute(name);
    	    // 打印结果 
    	    System.out.println("--sessionID"+session.getId());
    	    System.out.println("--名字:" + name +"-----\n");
    	    System.out.println("--值:" + vakue +"--------\n");
    	}
    	
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值