- 浏览: 678649 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (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中存放数据,尤其是大数据集合,在访问量比较大的网站有时甚至会产生严重的性能瓶颈。
这里仅就账号锁定和账号独立会话两个操作在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 1996package com.huatech.gateway.f ... -
logback 常用配置及说明
2020-05-28 15:41 710<?xml version="1.0& ... -
springboot中增强druid实现数据库账号密码加解密
2020-03-11 13:31 1557针对目前越来越严的安全等级要求,我们在做产品 ... -
java常用命令
2020-01-14 13:25 1092# 1、查询java进程id jps -v ... -
poi excel导入工具类
2019-11-20 14:00 716poi excel导入工具类ImportUtil i ... -
通过spring-context创建可执行jar
2019-04-23 13:52 11001、新建一个maven工程; 2、pom.xml中 ... -
什么情况下Java程序会产生死锁?如何定位和修复死锁
2019-04-18 20:38 1435死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此 ... -
反射机制和动态代理的原理
2019-04-13 14:02 1995反射机制是Java语言提供的一种基础功能,赋予程序在运行时 ... -
String、StringBuffer、StringBuilder的区别?
2019-04-13 10:00 752Java的基本类型有八种 ... -
强引用、软引用、弱引用、幻象引用有什么区别?具体使用场景是什么?
2019-04-12 15:10 753在 Java 语言中,除了原始数据类型的变量,其他 ... -
Exception与Error的区别?
2019-04-11 09:25 562Java语言在设计之初就 ... -
应用国际化(3)
2018-12-27 21:13 829前两篇介绍了应用国际化的注意事项和提示语国际化的简单实现。后 ... -
应用国际化(2)
2018-12-26 20:39 803上一篇介绍了应用国际化需要考虑的问题,本篇介绍后端如何实现 ... -
应用国际化(1)
2018-12-26 20:08 832最近在做数字资产交 ... -
性能优化实战-2
2018-09-28 10:15 1174我们在做架构设计的时候,会提到几个关键词:高性能、高 ... -
性能优化实战-1
2018-09-27 20:04 1115系统优化大致可以分 ... -
rabbitmq批量处理
2018-04-08 17:35 9442我们通过spring-amqp操作rabbitmq是极其简 ... -
java进程CPU过高问题定位
2018-03-14 09:06 22991、top命令查看过高CPU的pid,命令:top ... -
spring-boot集成RabbitMQ
2018-01-16 16:38 1311RabbitMQ的安装不在此赘述,想了解的可以参考: ... -
重写DispatcherServlet获取springmvc 所有RequestMapping的url
2018-01-09 10:41 30581、重写DispatcherServlet i ...
相关推荐
2. 存储到application中:将在线用户的信息保存在全局的`application`作用域内,例如Spring框架中的`ApplicationContext`。这种方法避免了频繁的数据库操作,但需要确保在用户退出时正确清理相关信息。 在本文提供...
在Java Web开发中,防止多用户重复登录是一个重要的安全措施,确保每个账号只能在一个设备或浏览器会话中活跃。常见的解决方法有两种,本文主要探讨第二种方案。 首先,第一种解决方案是通过在数据库中添加一个标志...
会话变量(Session)适合存储用户个人账号和权限数据。 8、正确答案:B。Request对象用于接收客户端发送的数据。 9、正确答案:C。`<title>`标签在HTML中可以单独出现,不需成对。 10、在WWW服务器和浏览器间主要...
- `sys/change_on_install`:具有最高权限的管理员账号,通常用于系统级别的管理操作。 - `system/manager`:标准的管理员账号,用于日常的数据库管理。 - `scott/tiger`:一个示例账号,用于演示和教学目的。 - `...
1. **API**:API,全称为Application Programming Interface,是软件系统之间交互的接口。在这个场景下,它可能是由服务器端提供的接口,允许客户端(如网页、移动应用)发送请求,进行用户登录和注册操作。 2. **...
- 确保数据库的安全性,包括设置用户权限,定期审计,防止未授权访问,以及处理账号锁定等问题。 10. 了解数据库版本特性: - 不同版本的Oracle数据库可能存在特性差异,如文中提到的Oracle 10g和9i的闪回功能,...
- 使用`v$lock`、`v$session`等视图查找锁定会话。 - 尝试终止异常会话(`alter system kill session ',<serial#>'`)。 - 分析`v$process`视图中的信息了解进程状态。 **4.3 执行RDA收集信息** - **RDA(Real ...
16.1.5 cookie的限制 16.2 使用会话状态 16.2.1 向会话状态中添加条目 16.2.2 从会话状态中删除条目 16.2.3 启动用户会话 16.2.4 结束用户会话 16.2.5 处理会话事件 16.2.6 在进程...
16.1.5 cookie的限制 16.2 使用会话状态 16.2.1 向会话状态中添加条目 16.2.2 从会话状态中删除条目 16.2.3 启动用户会话 16.2.4 结束用户会话 16.2.5 处理会话事件 16.2.6 在进程...
16.1.5 cookie的限制 16.2 使用会话状态 16.2.1 向会话状态中添加条目 16.2.2 从会话状态中删除条目 16.2.3 启动用户会话 16.2.4 结束用户会话 16.2.5 处理会话事件 16.2.6 在进程...
16.1.5 cookie的限制 16.2 使用会话状态 16.2.1 向会话状态中添加条目 16.2.2 从会话状态中删除条目 16.2.3 启动用户会话 16.2.4 结束用户会话 16.2.5 处理会话事件 16.2.6 在进程...
16.1.5 cookie的限制 16.2 使用会话状态 16.2.1 向会话状态中添加条目 16.2.2 从会话状态中删除条目 16.2.3 启动用户会话 16.2.4 结束用户会话 16.2.5 处理会话事件 16.2.6 在进程...
15.2.5 处理Application_BeginRequest事件 15.3 使用Web.Config文件 15.3.1 研究配置部分 15.3.2 修改配置设置 15.3.3 设置配置位置 15.3.4 锁定配置设置 15.3.5 添加自定义的...
解锁操作可以通过杀死锁定会话的进程来实现,例如: ```sql ALTER SYSTEM KILL SESSION 'sid, serial#'; ``` #### 31. SQLPLUS下如何修改编辑器? 可以使用`SET EDITOR`命令来更改SQL*Plus的编辑器。例如: ```sql ...
这是Oracle 9i Application Server Web Cache服务的默认登录凭证,用于管理Web缓存设置和服务状态。 #### 3. Oracle 8.0.5 创建数据库 使用`orainst`工具进行图形化安装。如果系统支持Motif界面,可以通过运行`...
在ASP中,开发者可以利用内置的对象如Request、Response、Session、Application等来处理HTTP请求、发送HTTP响应、管理用户会话以及共享应用程序级的数据。 回到“学生留言本 v1.0”,这个系统的核心组件包括以下几...
常见的几个账号包括: - `internal/oracle`:这个路径可能是指向某个特定的脚本或配置文件。 - `sys/change_on_install`:这是安装后默认的SYS用户的密码。 - `system/manager`:这是另一个默认的SYSTEM用户的...