下面是学习时,发现书上有段不错的代码,是说只允许一台机器的一个帐号登陆的,另外一个上线的话,会被注销掉。下面是代码;
<%
String action = request.getParameter("action");
String account = request.getParameter("account");
if("login".equals(action) && account.trim().length() > 0){
// 登录,将personInfo放入session
PersonInfo personInfo = new PersonInfo();
personInfo.setAccount(account.trim().toLowerCase());
personInfo.setIp(request.getRemoteAddr());
personInfo.setLoginDate(new java.util.Date());
session.setAttribute("personInfo", personInfo);
response.sendRedirect(response.encodeRedirectURL(request.getRequestURI()));
return;
}
else if("logout".equals(action)){
// 注销,将personInfo从session中移除
session.removeAttribute("personInfo");
response.sendRedirect(response.encodeRedirectURL(request.getRequestURI()));
return;
}
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
body {
font-size:12px;
}
</style>
</head>
<body>
<c:choose>
<c:when test="${ personInfo != null }">
<!-- 已经登录,将显示帐号信息 -->
欢迎您,${ personInfo.account }。<br/>
您的登录IP为${ personInfo.ip },<br/>
登录时间为<fmt:formatDate value="${ personInfo.loginDate }" pattern="yyyy-MM-dd HH:mm"/>。
<a href="${ pageContext.request.requestURI }?action=logout">退出</a>
<!-- 每5秒钟刷新一次页面 -->
<script>setTimeout("location=location; ", 5000); </script>
</c:when>
<c:otherwise>
<!-- 没有登录,将显示登录页面 -->
${ msg }
<c:remove var="msg" scope="session" />
<form action="${ pageContext.request.requestURI }?action=login" method="post">
帐号:
<input name="account" />
<input type="submit" value="登录">
</form>
</c:otherwise>
</c:choose>
PersonInfo.java:
public class PersonInfo implements Serializable {
private static final long serialVersionUID = 4063725584941336123L;
// 帐号
private String account;
// 登录IP地址
private String ip;
// 登录时间
private Date loginDate;
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Date getLoginDate() {
return loginDate;
}
public void setLoginDate(Date loginDate) {
this.loginDate = loginDate;
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof PersonInfo)) {
return false;
}
return account.equalsIgnoreCase(((PersonInfo) obj).getAccount());
}
listener.java:用MAP把登陆的session保存
public class LoginSessionListener implements HttpSessionAttributeListener {
Log log = LogFactory.getLog(this.getClass());
Map<String, HttpSession> map = new HashMap<String, HttpSession>();
public void attributeAdded(HttpSessionBindingEvent event) {
String name = event.getName();
// 登录
if (name.equals("personInfo")) {
PersonInfo personInfo = (PersonInfo) event.getValue();
if (map.get(personInfo.getAccount()) != null) {
// map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
HttpSession session = map.get(personInfo.getAccount());
PersonInfo oldPersonInfo = (PersonInfo) session
.getAttribute("personInfo");
log.info("帐号" + oldPersonInfo.getAccount() + "在"
+ oldPersonInfo.getIp() + "已经登录,该登录将被迫下线。");
session.removeAttribute("personInfo");
session.setAttribute("msg", "您的帐号已经在其他机器上登录,您被迫下线。");
}
// 将session以用户名为索引,放入map中
map.put(personInfo.getAccount(), event.getSession());
log.info("帐号" + personInfo.getAccount() + "在" + personInfo.getIp()
+ "登录。");
}
}
public void attributeRemoved(HttpSessionBindingEvent event) {
String name = event.getName();
// 注销
if (name.equals("personInfo")) {
// 将该session从map中移除
PersonInfo personInfo = (PersonInfo) event.getValue();
map.remove(personInfo.getAccount());
log.info("帐号" + personInfo.getAccount() + "注销。");
}
}
public void attributeReplaced(HttpSessionBindingEvent event) {
String name = event.getName();
// 没有注销的情况下,用另一个帐号登录
if (name.equals("personInfo")) {
// 移除旧的的登录信息
PersonInfo oldPersonInfo = (PersonInfo) event.getValue();
map.remove(oldPersonInfo.getAccount());
// 新的登录信息
PersonInfo personInfo = (PersonInfo) event.getSession()
.getAttribute("personInfo");
// 也要检查新登录的帐号是否在别的机器上登录过
if (map.get(personInfo.getAccount()) != null) {
// map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
HttpSession session = map.get(personInfo.getAccount());
session.removeAttribute("personInfo");
session.setAttribute("msg", "您的帐号已经在其他机器上登录,您被迫下线。");
}
map.put("personInfo", event.getSession());
}
}
还有一个小技巧就是:
MyContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
// 启动时,记录服务器启动时间
ApplicationConstants.START_DATE = new Date();
}
public void contextDestroyed(ServletContextEvent event) {
// 关闭时,将结果清除。也可以将结果保存到硬盘上。
}
ServletContextListener :监听context的创建与销毁的,当服务器启动或执行war包时,执行contextInitialized,关闭时执行
contextDestroyed
分享到:
相关推荐
标题中的“利用Spring Security控制同一个用户只能一次登录”是指在基于Spring Security的Web应用程序中实现单点登录(Single Sign-On, SSO)的功能,确保同一时间只有一个设备或浏览器会话可以登录同一用户的账户。...
为了实现登录人数的动态调整,你可能需要一个配置中心或在代码中设置一个可修改的静态变量来保存并发登录的限制值。在处理登录请求时,检查当前在线用户数是否超过这个限制,如果超过则拒绝登录,否则允许登录并更新...
1. **修改`listener.ora`配置文件**:首先需要确保监听器的配置文件`listener.ora`中启用了`OS_AUTHENT_PREFIX`参数,并将其值设置为一个特定的前缀,如“OS_”。这样,任何试图通过操作系统认证方式进行认证的连接...
在Java Web开发中,确保用户在同一时间只能在一个设备上登录是一项重要的安全性需求。这通常通过实现Session监听器来实现。本文将深入探讨如何利用Session监听器来防止同一用户在多个客户端同时登录。 首先,理解...
说明: 指定一个字符串值, 设置 TIME 数据类型的默认值, 该数据类型包含 HOUR, MINUTE 和 SECOND 这几个日期时间字段。 语法: TIME '09:26:50' (将值存储为 7 个字节)。 默认值: 从 NLS_TERRITORY 中获得 nls_time...
在"Servlet高级应用"这个主题中,我们将深入探讨Servlet的一些高级特性和实践技巧,这些内容将帮助开发者更好地构建高效、可扩展的Web应用程序。 1. **生命周期管理**: Servlet的生命周期包括初始化、服务和销毁...
标题"安卓Android源码——tablelogin(登陆界面).zip"表明这是一个关于安卓Android操作系统的源码项目,特别关注的是一个名为"tablelogin"的登录界面。"tablelogin"可能是该界面的设计或者组件名称,可能采用了表格...
当用户登录后,服务器会创建一个Session,并将用户信息存储在其中,以便在后续的请求中识别和管理用户。而Session监听器则可以帮助我们更有效地管理和监控这些Session。 首先,我们需要了解如何定义一个Session监听...
通常,它会包含一个Android Studio项目,展示了如何在实际代码中应用上述理论知识。 总的来说,`AutoCompleteTextView`结合`Filter`能够为登录界面提供智能化的用户名输入辅助,降低用户输入难度,提高登录效率。...
在C#中,我们可以创建一个TcpListener实例来监听指定的端口,等待客户端的连接请求。一旦有客户端连接,就可以建立一个TcpClient实例与之交互。通过NetworkStream对象,我们可以读写网络流中的数据,实现消息的发送...
Envoy是一个由Lyft公司开发的高性能网络代理,现已成为Cloud Native Computing Foundation (CNCF) 的关键项目,它在云原生环境中广泛用于服务网格、API 网关和微服务架构。Envoy 以其强大的可扩展性和灵活性著称,...
转发是在服务器端内部完成的,请求从一个Servlet传递到另一个Servlet或JSP页面,客户端浏览器并不知道这个过程。重定向则是服务器告诉客户端浏览器去访问另一个URL,客户端会发起一个新的请求。 在实际开发中,我们...
- **事件驱动**: 可以创建一个自定义的`LoginAttempts`事件,每次用户尝试登录或其他操作时触发。事件监听器则负责计数并判断是否超过限制。 - **中间件**: 使用Laravel的中间件机制,在用户尝试执行操作前检查其...
这款应用提供了用户注册、登录、发布文章、评论互动、论坛讨论等功能,是一个完整的Web应用程序示例,有助于学习和理解JSP开发。 JSP是一种动态网页技术,由Sun Microsystems(现已被Oracle收购)在1999年推出,...
10. **性能优化**:了解Servlet源代码有助于优化性能,例如,通过实现`SingleThreadModel`接口限制一个Servlet实例只能服务于一个请求,或者使用Servlet 3.0的注解驱动配置减少XML配置的复杂性。 通过深入学习和...
一个Java Web应用通常包含WEB-INF目录,其中web.xml是应用的部署描述符,定义了应用的配置信息。应用可以被打包为WAR(Web Archive)文件,然后部署到服务器上。 10. **JNDI(Java Naming and Directory Interface...
Servlet 2.3规范是Java Web开发中的一个重要里程碑,它为服务器端的Java应用程序定义了标准接口和行为。这个规范由Sun Microsystems(现为Oracle)发布,并被广泛应用于各种Web应用服务器,如Tomcat、Jetty等。在这...
当用户尝试超出限制的登录次数时,Spring Security会抛出一个`SessionAuthenticationException`,你可以自定义处理这个异常,比如显示一个友好的错误页面。 为了增强用户体验,你还可以添加一些额外的逻辑,例如...
Apache SSHD是一个开源的Java实现,它提供了对SSH(Secure SHell)协议的支持,使得开发者能够在Java应用程序中构建SSH服务器和客户端。SSH是一种用于安全远程登录、文件传输和其他网络服务的协议,它通过加密技术...
Java Web开发是Java技术的一个重要领域,它主要关注于开发基于Web的应用程序,通常是指运行在服务器端,由客户端通过Web浏览器访问的应用程序。下面是从提供的文件内容中整理出的Java Web开发相关知识点。 ### ...