一个用户只能登录一次
仅仅思路,这是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();}@Overridepublic 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)*/@Overridepublic void sessionCreated(HttpSessionEvent httpSessionEvent) {System.out.println("创建session");}/*** 删除session时(退出系统)*/@Overridepublic 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 {@Beanpublic 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) {//当前会话IDString 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不等于当前会话IDif (null != oldSessionsInfo && oldSessionsInfo.size() > 0 && !oldSessionsInfo.get(0).getSessionId().equals(currentSessionId)) {//遍历已经登录用户的会话信息,并设置过期,即删除sessionfor (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");}}
}
一个用户只能登录一次相关推荐
- ASP.NET MVC实现一个用户只能登录一次 单用户登录
现在许多网站都要求登录后才能进行进一步的操作,当不允许多用户同时登录一个帐号时,就需要一种机制,当再登录一个相同的帐号时,前面登录的人被挤下线,或者禁止后面的人登录.这里实现的是前一种功能. 网上有许 ...
- 《指定一个用户只能在特定的时间里不能登陆》『罗斌原创』
<指定一个用户只能在特定的时间里不能登陆> 使用有管理员权限的用户登陆(administrator),进入命令模式下以GUEST这个用户为列 如果需要设置这个GUEST帐户从周一到周五的早 ...
- oracle 创建一个用户,只能访问指定的对象
今天在开发接口时候,需要给接口开发公司提供一个ORACLE 用户,只能访问指定的表或视图,把过程记录到此 1.创建一个ORACLE 的用户 create user username identifie ...
- (Java)实现一个用户密码登录的弹窗界面
目录 一.前言 二.涉及到的知识点代码 三.代码部分 四.程序运行结果(弹出) 一.前言 1.本代码是我在上学时写的,有一些地方没能完美实现,请包涵也请多赐教! 2.本弹窗界面可以根据简单的要求进行输 ...
- linux 没有权限登录,CentOS中让一个用户没有登录权限
一.还未建立用户时,可以使用以下命令 1,groupadd groupname useradd -g groupname username -s /bin/false #-s为默认shell,不给 ...
- 防止用户重复登录解决方案
前一段时间碰到一个需求:一个账号只能登录一次,不能重复登录问题. 在网上找了下,大概有两种解决方案: 1.通过数据库状态位判断该用户是否已经登录. 2.利用session监听器监听每一个登录用户的登录 ...
- 一个手机里登录2个微信号(微信双开)
正常来说,使用微信的客户端,一个手机只能登录一个微信号. 所以,另一个微信号就需要第三方的工具来实现. 我的环境:android (苹果的APPStore 好像没有我使用的这款软件) 重点来了,这是款 ...
- WordPress查看上次用户何时登录插件When Last Login
如果你的 WordPress 站点是多人联合管理和开放用户注册功能的大型博客网站,那么想要查看上次用户何时登录您的 WordPress 网站,建议安装这款轻巧 When Last Login 插件.该 ...
- java中限制多人登录的_Spring Boot + Spring Security 防止用户在多处同时登录(一个用户同时只能登录一次)及源码分析...
网上很多文章的实现方法写得比较复杂 这里介绍一个简单的方法. 实现 @Configuration @EnableWebSecurity public class SecurityConfigurati ...
最新文章
- python面向对象开发(类的属性-精讲
- 计算feature map大小
- Android View的事件分发机制解析
- Debian 新负责人发表演讲:Debian 的现状与面临的一些问题
- aspx隐藏前台控件div_c# – 代码隐藏页面无法“查看”aspx页面中声明的任何项目/控件...
- Spring Boot2 整合 Shiro ,两种方式全总结!
- 计算机黑屏策略,小黑w7系统诊断策略服务已被禁用的还原教程
- 《史无前例!编程语言python斩获最有发展第一与排行榜第三!》深入 Python 流程控制
- winform 读取用户控件的变量_winform中用户控件之间的传值
- 实现一个闹钟_iOS 14 闹钟:为啥这么难用?
- 机械工程师手册 pdf版下载_机械设计问题 简明手册介绍的还是很全面详尽的(附PDF手册)...
- iPhone手机越狱不只是为了安装盗版应用、越狱的十大好处
- win10更改hosts文件
- JS利用for多重循环制作9*9乘法表
- 初夏小谈:结构体内存对齐详解
- 【Python】胡渊鸣的99行代码——冰雪奇缘
- mtatlas mysql_MHA-Atlas-MySQL高可用(下)
- Mac电脑上如何关闭屏幕时间
- 【web学习之Mysql】数据库-----查询操作------大全
- 【听】你会杀死那个胖子吗?功利与道德的选择