JEE保证登陆唯一
来源:互联网 发布:东莞知路电子有限公司 编辑:程序博客网 时间:2024/05/22 14:21
在做上个课程项目的时候就遇到过这个问题,当时的实现方式 是通过全局的监听来实现的,通过session 来标记一个用户的登陆状态,只有当当前用户注销时 用户用同样的账号登陆才会成功,这个做法存在多个问题,其中主要问题是判断用户登出,如果用户点击注销键,这个没问题,但是如果用户异常登出呢? 当然也不是没有办法,首先 我们可以设立监听事件 unload 这样在网页关闭的时候会触发这个时间, 但是这个事件会被多个动作触发,部分动作并不表示退出,比如说网页刷新等,另外直接关闭浏览器主窗体也不会触发标签页的unload事件, 当然还有方法补救, 我们通过session的 生命周期来, 如果用户在session 生命周期内没有与服务器发生交互 我们就认为用户已经离开,这个也是一个较为稳妥的方法,这个方法存在一个问题 如果用户异常登出, 那么用户需要等待当前session 会话结束才能再次登陆, 这个也是我上个项目没有实现这个功能的主要理由
现在换了一种决策,我认为登陆是可以互顶的,后登陆的会顶掉先登录的人,这样的逻辑思维也比较正常,如果一个人多处登陆,那么他使用最后登陆的设备与服务器交互的可能性也最大,如果存在异常一个人账号被多个人知晓,他也能通过互顶账号来实现保护自己的账号安全,检查互顶频率 也可以实现账号冻结等功能,
扯完背景了 扯点实在的
这里采用的方式是struts 的拦截器 我通过静态的map 存储userid 到 sessionid 的映射 然后通过检查映射来完成引导
这里复用了我一个测试的项目 代码逻辑就不用管了 只看实现就成
首先定义通用方法 使用单例 管理map 对象 同时 考虑多线程访问
package com.yueguang.util;import java.util.HashMap;import java.util.concurrent.Semaphore;public class AccountUtil {private static AccountUtil accountUtil= new AccountUtil();private HashMap<String, String> accountToSession;Semaphore semaphore;private AccountUtil() { accountToSession = new HashMap<String, String>(); semaphore = new Semaphore(1);}public static AccountUtil getAccountUtil() {return accountUtil;}public synchronized void registerSessionid(String account, String sessionid) {try {semaphore.acquire();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}accountToSession.put(account, sessionid);System.out.println(account+" " + sessionid);semaphore.release();}public synchronized boolean checkSessionid(String account, String sessionid) {try {semaphore.acquire();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}String old_sessionid = accountToSession.get(account);semaphore.release(); System.out.println("1111 " + old_sessionid); System.out.println(account + " "+ sessionid);if (old_sessionid != null && old_sessionid.equals(sessionid)) {return true;} else {return false;}}}
其次定义拦截器 拦截请求 交给验证 如果验证失败 引导到重新登录的页面
package com.yueguang.Interceptor;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.apache.struts2.ServletActionContext;import org.apache.struts2.interceptor.ServletRequestAware;import org.apache.struts2.interceptor.SessionAware;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;import com.yueguang.util.AccountUtil;public class LoginInterceptor extends AbstractInterceptor {Map<String, Object> session;HttpServletRequest request;@Overridepublic String intercept(ActionInvocation actionInvocation) throws Exception {// TODO Auto-generated method stubAccountUtil accountUtil = AccountUtil.getAccountUtil();session = actionInvocation.getInvocationContext().getSession();if (session == null) {return "reLogin";}String userid = (String) session.get("userid");if (userid == null) {return "reLogin";}request = ServletActionContext.getRequest();String sessionid = (String) request.getSession().getId();if (accountUtil.checkSessionid(userid, sessionid)) {return actionInvocation.invoke();} else {return "reLogin";}}}
然后在登陆成功的时候 想session 中注入用户名 并且向map中 注入键值对
// 实现登陆功能的通用模块private String loginUtil(Class c) {Object someone = baseDao.load(c, username);Method m;try {m = c.getMethod("getPassword", null);if (someone != null&& ((String) m.invoke(someone)).equals(password)) {request.setAttribute(c.getName().substring(c.getName().lastIndexOf(".") + 1),someone);<span style="color:#ff0000;">AccountUtil accountUtil = AccountUtil.getAccountUtil();accountUtil.registerSessionid(username, request.getSession().getId()); session.put("userid", username);</span>return SUCCESS;}} catch (NoSuchMethodException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}this.addActionError("用户 " + username + "用户类型 "+ c.getName().substring(c.getName().lastIndexOf(".") + 1)+ " 登陆失败 ");return "fail";}
配置struts 拦截器
<package name="checkLogin" extends="struts-default"> <interceptors> <interceptor name="login" class="com.yueguang.Interceptor.LoginInterceptor"/> <interceptor-stack name="login_default"> <interceptor-ref name="login"/> <interceptor-ref name="defaultStack"/> </interceptor-stack> </interceptors> <default-interceptor-ref name="login_default"/> </package>
让需要改拦截器的模块扩展 这个包
<package name="test" namespace="/test" extends="<span style="color:#ff0000;">checkLogin</span>"> <global-results> <result name="reLogin">/Login.jsp</result> </global-results> <action name="haha" class="testAction" method="test"> <result name="success">/Error.jsp</result> <result name="fail" type="chain"> <param name="actionName">kaka</param> <param name="namespace">/test</param> </result> </action> <action name="kaka" class="testAction" method="testkaka"> <result name="success">/Error.jsp</result> <result name="fail">/Login.jsp</result> </action> </package>
这个方法能实现单人登陆的效果,但是存在个问题是 转发的请求 也会被拦截器 检测 这个会导致效率低下 我正在查不拦截 dispatcher 的方法
- JEE保证登陆唯一
- 唯一登陆
- left join不能保证唯一
- TreeSet保证元素唯一性
- HashSet保证元素唯一性
- 保证文件名的唯一性
- JSP 唯一登陆判断
- JEE
- JEE
- 如何保证上线用户的唯一性
- 如何保证全局变量的唯一性?
- 插件开发中id一定要保证唯一
- 内存映射-保证程序唯一运行
- 如何保证全局变量的唯一性?
- CLSID Type Library 保证全球唯一
- 保证执行的进程唯一性
- 保证tableview Checkmark的选中唯一性
- HashSet保证元素唯一性原理图解
- Android Framework基础一
- 20150612_OC之数组及复合类的练习
- 男生需要赚多少钱才够维系家庭
- CentOS 6.4下PXE+Kickstart无人值守安装操作系统
- [055] SSL 3.0曝出Poodle漏洞的解决方案-----开发者篇
- JEE保证登陆唯一
- HBase Shell的基本用法
- 技术演绎之 [ java ] 初步认识
- IOS开发-UIView之动画效果的实现方法
- 2015百度之星复赛(hdu5258 - 5262)
- Java程序员学习C++之常量指针和指针常量
- 语义化版本2.0.0
- 常用esb介绍
- 数据库小实验