- 浏览: 661027 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (141)
- java (58)
- SQL (7)
- java开源 (2)
- javascript (3)
- struts2 (2)
- oracle (6)
- junit (1)
- js报表 (1)
- jQuery (5)
- 插件安装 (1)
- myeclipse (1)
- xfire (1)
- weblogic (1)
- hibernate (6)
- loading (1)
- jbpm (3)
- 物语 (0)
- android (14)
- spring (20)
- BigDecimal (1)
- view (1)
- 总结 (2)
- application (1)
- Netty (5)
- aop (1)
- redis (7)
- double (1)
- restful (1)
- cache (3)
- profile (1)
- redisTemplate (1)
- poi (3)
- excel导出 (1)
- mysql (7)
- group (4)
- replication (4)
- proxysql (1)
- windows (1)
- version (1)
- mongodb (2)
- RocketMQ (1)
- MQ (1)
- RSA (1)
- 日志 (2)
- ip (1)
- socket (1)
- hibernate-validator (1)
- delayQueue (1)
- spring-retry (1)
- rabbitmq (3)
- httpclient (1)
- tools (1)
- 增量发布 (1)
- web (3)
- spring-boot (5)
- druid (2)
- pageHelper (1)
- freemarker (1)
- RequestMapping (1)
- 性能优化 (2)
- springBoot (1)
- docker (2)
- 安全 (0)
- 国际化 (3)
- websocket (1)
- stomp (1)
- shiro (1)
- 网络安全 (2)
- 锁 (1)
- logback (1)
最新评论
-
changerzhuo_319:
谢谢大佬, 查了一天了没解决
Spring-boot构建多模块依赖工程时,maven打包异常:程序包xxx不存在 -
迪伦少校:
spring越来越优秀的同时,也越来越复杂
spring核心技术(1) -
hbxflihua:
ivi13 写道这种方式会有个问题,假如有个商户的交易量特别大 ...
使用spring-retry实现支付系统异步通知 -
ivi13:
这种方式会有个问题,假如有个商户的交易量特别大,通知全部失败, ...
使用spring-retry实现支付系统异步通知 -
ckxlnd:
挺好的 有借鉴意义
重写DispatcherServlet获取springmvc 所有RequestMapping的url
Application级账号锁定及账号独立会话操作
- 博客分类:
- application
- java
Application用于存放应用程序级的共享数据,比如用户访问量统计、防止同一账号同一时间多客户端登录等等。一般而言,我们不建议在application中存放数据,尤其是大数据集合,在访问量比较大的网站有时甚至会产生严重的性能瓶颈。
这里仅就账号锁定和账号独立会话两个操作在application中的应用做一个简单的介绍,不妥之处,望不吝赐教。
账号锁定
同一账号连续N次(可配置)登录(login_count)密码有误,则锁定该账号。账号锁定后,该用户在持续锁定时间(lock_time)范围(比如24小时)内不允许登录。超过持续锁定时间后,再次登录,重新计算登录次数。拿网上银行系统举例(可能不太恰当)。网上银行系统一般都规定在一天内,密码连续三次输入错误,则该账号被锁定。
账号独立会话
类似于QQ的功能,一个账号只能在一个客户端(这里可以指一台电脑或者一个会话,不过原理差不来多少,本示例基于session)进行操作,采取后来居上,前客户端登录直接被踢的方式。可能提炼的不够恰当,暂且就这么叫吧,朋友们有更好的术语不妨留言讨论。当然也可以在登录时,判断该账号是否已登录,如果已经登录则给予提示。方法不尽相同,不过殊途同归。
我打算将这两个功能合在一起,主要是基于都是application级应用的考虑。下面谈谈具体的实现方案。
概要说明
这里需要记录下账号的相关信息,所以需要一个POJO类,需要一个拦截器来验证账号信息。
具体描述
在用户登录时,记录下账号信息如登录名、sessionId、最后登录时间、连续错误登录次数等等。以登录名为key,账号信息为value存放在Map集合中,并将Map置于application。
用户每次登录都记录下登录时间,,登录错误则错误登录次数加一。连续错误登录,次数超过限制,则不允许继续登录。超出锁定时间后,再次登录时,连续错误登录次数清零,从而实现账号锁定的功能。
同一账号只会记录该账号最后一次登录的sessionId。在拦截器中对用户的会话ID进行验证,如果不一致,则为之前登录的客户端,直接将当前会话清除,以实现账号独立会话的功能。
具体示例代码如下:
import java.util.Date; /** * 登录信息 * @remark 该信息保存在application中,主要用于登录锁定和同一账户同时只能登录一次 * @author lihua * @version V1.0 * @createDate 2012-9-28 */ public final class LoginInApp { private String sessionId;//保存当前用户最新的sessionid private Date loginTime;//最后登录时间 private int loginCount;//连续错误登录次数,该次数会在登录超过可连续登录时间间隔后自动回位到1 public LoginInApp() { } public LoginInApp(String sessionId, Date loginTime, int loginCount) { this.sessionId = sessionId; this.loginTime = loginTime; this.loginCount = loginCount; } public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } public Date getLoginTime() { return loginTime; } public void setLoginTime(Date loginTime) { this.loginTime = loginTime; } public int getLoginCount() { return loginCount; } public void setLoginCount(int loginCount) { this.loginCount = loginCount; } }
账号锁定验证代码
/** * 账号锁定验证 */ String accountLockState = PropertiesUtil.getString(Constants.ACCOUNT_LOCK_STATE);//锁定状态开关 if(ValidateUtil.matchString(accountLockState, "on")){ //开启锁定 HttpSession session = request.getSession(); Object obj = session.getServletContext().getAttribute(Constants.KEY_SESSION_MESSAGE); if(obj!=null){ //application 用户缓存不为空 Map<String, LoginInApp> map = (HashMap<String, LoginInApp>)obj; LoginInApp lip = map.get(userdto.getUserName()); if(lip!=null){ //当前用户的登录记录不为空 int max_login_number = 3;//可连续登录次数 int lock_time = 10;//持续锁定时间 SysParam param = sysParamServiceImpl.getByParamName(Constants.SECURITY_PARAMS[0]); if(param!=null&&ValidateUtil.validateString(param.getParamValue())){ max_login_number = Integer.valueOf(param.getParamValue()); } SysParam param1 = sysParamServiceImpl.getByParamName(Constants.SECURITY_PARAMS[1]); if(param1!=null&&ValidateUtil.validateString(param1.getParamValue())){ lock_time = Integer.valueOf(param1.getParamValue()); } if(lip.getLoginCount()>=max_login_number){ //超出可连续登录次数 Calendar curCal = Calendar.getInstance(); Calendar lockCal = new GregorianCalendar(); lockCal.setTime(lip.getLoginTime()); lockCal.add(Calendar.MINUTE, lock_time); if(curCal.before(lockCal)){ addActionError("账号"+userdto.getUserName()+"已被锁定,请在"+lock_time+"分钟后登录!"); return "loginerror"; }else{//过期解锁 lip.setLoginCount(0); } } } } }
/**
* 修改应用程序缓存账户信息 * @param user */ private void modifyLoginInApp(OnlineUser user){ String accountLockState = PropertiesUtil.getString(Constants.ACCOUNT_LOCK_STATE);//锁定状态开关 if(ValidateUtil.matchString(accountLockState, "on")){ //锁定状态开启 ServletContext app = ServletActionContext.getServletContext(); //上下文 Map<String, LoginInApp> appInfo = (Map<String, LoginInApp>)app.getAttribute(Constants.KEY_SESSION_MESSAGE); if(ValidateUtil.matchString(user.getErrorMsg(),Constants.LOGIN_ERROR_TIP)){//登录异常 if(appInfo!=null){ LoginInApp lip = appInfo.get(user.getUserName()); if(lip==null){ lip = new LoginInApp(ServletActionContext.getRequest().getSession().getId(),new Date(),1); }else{ lip.setLoginTime(new Date()); lip.setLoginCount(lip.getLoginCount()+1); } appInfo.put(user.getUserName(), lip); }else{ appInfo = new HashMap<String, LoginInApp>(); LoginInApp lip = new LoginInApp(ServletActionContext.getRequest().getSession().getId(),new Date(),1); appInfo.put(user.getUserName(), lip); } app.setAttribute(Constants.KEY_SESSION_MESSAGE, appInfo); } } }
private void sessionManage(OnlineUser user){
HttpSession session = request.getSession(); ServletContext context = ContextLoader.getCurrentWebApplicationContext().getServletContext(); Object obj = context.getAttribute(Constants.KEY_SESSION_MESSAGE); Map<String, LoginInApp> map = null; if(obj!=null){ map = (HashMap<String, LoginInApp>)obj; }else{ map = new HashMap<String, LoginInApp>(); } map.put(user.getUserName(),new LoginInApp(session.getId(),new Date(),0)); context.setAttribute(Constants.KEY_SESSION_MESSAGE,map); }
在拦截器中处理多客户端登录
OnlineUser ouser = (OnlineUser)session.getAttribute(Constants.KEY_SESSION_ONLINE_USER); //多个客户端登录,先登录者被踢出 ServletContext context = session.getServletContext(); Object obj = context.getAttribute(Constants.KEY_SESSION_MESSAGE); if(obj!=null&&ouser!=null){ Map<String, LoginInApp> map = (HashMap<String, LoginInApp>)obj; String oldSessionId = map.get(ouser.getUserName())==null?null:map.get(ouser.getUserName()).getSessionId(); if(ValidateUtil.validateString(oldSessionId)&&!ValidateUtil.matchString(session.getId(), oldSessionId)){ session.removeAttribute(Constants.KEY_SESSION_ONLINE_USER); response.sendRedirect(request.getContextPath() + "/common/outTime.jsp"); return; } }
评论
个人认为数据存至应用的Applicaion中,对于大应用会耗费内存影响性能,我们在做项目组时都是通过数据库来实现这些功能的。
发表评论
-
Spring Gateway 接口返回值脱敏
2023-10-20 09:55 1605package com.huatech.gateway.f ... -
logback 常用配置及说明
2020-05-28 15:41 494<?xml version="1.0& ... -
springboot中增强druid实现数据库账号密码加解密
2020-03-11 13:31 1285针对目前越来越严的安全等级要求,我们在做产品 ... -
java常用命令
2020-01-14 13:25 732# 1、查询java进程id jps -v ... -
poi excel导入工具类
2019-11-20 14:00 498poi excel导入工具类ImportUtil i ... -
通过spring-context创建可执行jar
2019-04-23 13:52 8931、新建一个maven工程; 2、pom.xml中 ... -
什么情况下Java程序会产生死锁?如何定位和修复死锁
2019-04-18 20:38 1235死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此 ... -
反射机制和动态代理的原理
2019-04-13 14:02 1907反射机制是Java语言提供的一种基础功能,赋予程序在运行时 ... -
String、StringBuffer、StringBuilder的区别?
2019-04-13 10:00 656Java的基本类型有八种 ... -
强引用、软引用、弱引用、幻象引用有什么区别?具体使用场景是什么?
2019-04-12 15:10 674在 Java 语言中,除了原始数据类型的变量,其他 ... -
Exception与Error的区别?
2019-04-11 09:25 493Java语言在设计之初就 ... -
应用国际化(3)
2018-12-27 21:13 723前两篇介绍了应用国际化的注意事项和提示语国际化的简单实现。后 ... -
应用国际化(2)
2018-12-26 20:39 694上一篇介绍了应用国际化需要考虑的问题,本篇介绍后端如何实现 ... -
应用国际化(1)
2018-12-26 20:08 748最近在做数字资产交 ... -
性能优化实战-2
2018-09-28 10:15 1052我们在做架构设计的时候,会提到几个关键词:高性能、高 ... -
性能优化实战-1
2018-09-27 20:04 1002系统优化大致可以分 ... -
rabbitmq批量处理
2018-04-08 17:35 9180我们通过spring-amqp操作rabbitmq是极其简 ... -
java进程CPU过高问题定位
2018-03-14 09:06 22211、top命令查看过高CPU的pid,命令:top ... -
spring-boot集成RabbitMQ
2018-01-16 16:38 1230RabbitMQ的安装不在此赘述,想了解的可以参考: ... -
重写DispatcherServlet获取springmvc 所有RequestMapping的url
2018-01-09 10:41 28271、重写DispatcherServlet i ...
相关推荐
Rich Internet Application高级编程:后AJAX时代.rarRich Internet Application高级编程:后AJAX时代.rarRich Internet Application高级编程:后AJAX时代.rarRich Internet Application高级编程:后AJAX时代.rar
ConsoleApplication1-伪线程及独立栈.zip
delphi的ExcelApplication控件excel操作
从MATLAB中创建出一个独立的应用程序有多种方法,可以用MATLAB提供的现有函数或者现有App,本文介绍的是利用MATLAB的Application Compiler工具创建一个独立的应用程序。
Java实现同一账号限制同时登录,里面是源码,写得很清楚。利用application实现的,入门选手的福利
Android操作Application的代码例子。用于演示通过Application来实现读写内存的功能,其中Application实例需要采用单例模式。
AVAYA IP Office System Status Application操作中文手册.pdf
好玩不关闭 application/x-dosexec application/x-dosexec application/x-dosexec application/x-dosexec application/x-dosexec application/x-dosexec application/x-dosexec application/x-dosexec ...
IBM HACMP 高级功能 APPLICATION MONITOR介绍
依靠系统自带的Appcmd.exe工具, 进行添加Applicaiton Pool, Application及给Application分配Application Pool的操作. 在文件 Install.bat中, 有一些基本参数设置 Rem CreateAppPool_IIS7.bat appPoolName[required]...
ExcelApplication1.Caption:='Excel Application'; ExcelApplication1.Workbooks.Add(Null,0); ExcelWorkbook1.ConnectTo(ExcelApplication1.Workbooks[1]); ExcelWorksheet1.ConnectTo(ExcelWorkbook1....
application.xml配置文件详解 application.xml配置文件详解 application.xml配置文件详解
可以通过微软自己的Microsoft Application Compatibility Toolkit 5.5将信任程序加入系统白名单。使用方法: 1. 安装后得到三个程序,我们需要使用管理员权限启动Compatibility Administrator; 2. 在Custom ...
yarn编码,实现Application列表查询,Application的kill操作。以及Job的查询,map和reduce个数查询
本文介绍C#访问操作Access数据库的基础知识,并提供一个相关的例程。 1.通过ADO.NET的OleDb相关类来操作Access 主要知识点如下: using System.Data.OleDb; using System.Data; 连接字符串:String connectionString...
从application启动activity
Application.ProcessMessages作用Application.ProcessMessages作用Application.ProcessMessages作用Application.ProcessMessages作用
application类使用示例,在多个activity中传递数据
ACT5.5即Application Compatibility Toolkit Version 5.5(应用程序兼容工具包5.5版),它提供了可帮助用户针对特定程序与Windows XP/Vista操作系统兼容性问题加以诊断和解决的文档及工具。通过安装该工具可以解决...