有关登录限制综合案例的疑问

来源:2-4 实现动态图表

哆丶哆

2019-07-13 17:57:35

老师,在学习本章的综合案例时,主要是实现用户登录限制的功能:即一个用户在同一时间只能在一个浏览器上登录,第二次登录同账户时,会把原账户“踢下去”。我看了视频讲解以及相关代码,如下是实现逻辑功能的相关的java类,我发现思想大致是这样的:

  1. 用户第一次登录,触发session添加属性的监听方法,为用户名设置sessionID和session对象的映射,顺利登录系统

  2. 用户第二次在别处登录时(用户名和第一次一样),在填写用户名点击登录时候,触发了session添加属性的监听方法,会判断出这个用户名所映射的sessionID是否为空,不为空说明之前已经有登录过,则要清空之前的session,重新为用户名映射新的sessionID和session对象

  3. 第一次登录用户的地方,由于session会话信息被清空了,当再次访问首页时,由于没有登录信息,会被拦截器拦截,强制进入登录页面,需要重新登录

对此,学生产生的几个疑问:

    1.请问我对本项目的实现思想理解正确么?

    2.如果我理解无误,那么,我想象有这么一个情况:张三和李四同时在A电脑的浏览器打开不同窗口分别登录系统,因为是在同一个浏览器,所以张三和李四所用的session会话对象应该是同一个。这时,第三个人在B电脑登录了张三的帐号,按照代码逻辑,应该把张三之前映射的session对象数据清空,重新在B电脑生成的新的session对象与张三用户名进行重新映射。可是这样的话,虽然张三能被顺利限制登录,但是和他公用一个session对象的李四不也被一起“踢出系统”了么?可是现实中并没有人在其他地方登录李四的账号呀。那要怎么在代码中防止这种不合理的情况发生呢?

    3.从代码上可以看出,用户名和session的相关映射关系被保留到同一个LoginCache类的单例对象 中,请问,这个对象的生命周期是多长呢?是从被创建开始就一直存在,直到服务器关闭销毁么?

单例对象LoginCache.java:

package com.imooc.cache;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;
/**
 * 登录用户与session缓存对象
 * @author lv
 *
 */
public class LoginCache {
	private static LoginCache instance = new LoginCache();
	
	private Map<String,String> loginUserSession = new HashMap<String,String>();// key值:登录用户登录名,value值:登录用户sessionId
	private Map<String,HttpSession> loginSession = new HashMap<String,HttpSession>();//key值:登录用户sessionId,value值:登录用户session对象
	
	private LoginCache(){
		
	}
	
	public static LoginCache getInstance(){
		return instance;
	}
	/**
	 * 通过登录名获取对应登录用户的sessionId
	 * @param username
	 * @return
	 */
	public String getSessionIdByUsername(String username){
		return loginUserSession.get(username);
	}
	
	/**
	 * 通过sessionId获取对应的session对象
	 * @param sessionId
	 * @return
	 */
	public HttpSession getSessionBySessionId(String sessionId){
		return loginSession.get(sessionId);
	}
	
	/**
	 * 存储登录名与对应的登录sessionID至缓存对象
	 * @param username
	 * @param sessionId
	 */
	public void setSessionIdByUserName(String username,String sessionId){
		loginUserSession.put(username, sessionId);
	}
	
	/**
	 * 存储sessionId与对应的session对象至缓存对象
	 * @param sessionId
	 * @param session
	 */
	public void setSessionBySessionId(String sessionId,HttpSession session){
		loginSession.put(sessionId, session);
	}

}

过滤器SessionFilter.java:

package com.imooc.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 用户登录权限过滤器
 * @author lv
 *
 */
public class SessionFilter implements Filter {

	@Override
	public void destroy() {

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest hrequest = (HttpServletRequest)request;
		HttpServletResponse hresponse = (HttpServletResponse)response;
		
		String loginUser = (String)hrequest.getSession().getAttribute("loginUser");//从session对象中获取登录用户名
		
		if(loginUser==null){//登录用户名不存在,用户未登录,强制重定向至登陆页面
			hresponse.sendRedirect(hrequest.getContextPath()+"/index.jsp?flag=1");
			return;
			
		}else{
			chain.doFilter(request, response);//已登录,转入相应的请求处理
			return;
		}

	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {

	}

}

监听器LoginSessionListener .java:

package com.imooc.listener;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

import com.imooc.cache.LoginCache;
/**
 * 用户登录监听器
 * @author lv
 *
 */
public class LoginSessionListener implements HttpSessionAttributeListener {
	
	private static final String LOGIN_USER="loginUser";

	@Override
	public void attributeAdded(HttpSessionBindingEvent hsbe) {
		String attrName = hsbe.getName();//监听到session属性值发生添加操作,获取对应操作的属性名
		
		if(LOGIN_USER.equals(attrName)){//若属性名为登录属性名,判定为用户登录操作
			String attrVal = (String)hsbe.getValue();//获取添加的属性值,即用户登录名
			HttpSession session = hsbe.getSession();//该次操作的session对象
			String sessionId = session.getId();//该次操作的session对象ID
			
			String sessionId2 = LoginCache.getInstance().getSessionIdByUsername(attrVal);//从缓存对象里面,获得该用户登录名对应的sessionID值
			if(null == sessionId2){//未获得结果,不需要清理前次登录用户会话信息
				
			}else{
				HttpSession session2 = LoginCache.getInstance().getSessionBySessionId(sessionId2);//获取前次该用户登录对应的session对象
				session2.invalidate();//清理前次登录用户会话存储信息,使得前次登录失效
			}
			
			//完成该次登录用户登录名、sessionID,session对象的缓存对象存储
			LoginCache.getInstance().setSessionIdByUserName(attrVal, sessionId);
			LoginCache.getInstance().setSessionBySessionId(sessionId, session);
			
		}

	}

	@Override
	public void attributeRemoved(HttpSessionBindingEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void attributeReplaced(HttpSessionBindingEvent arg0) {
		// TODO Auto-generated method stub

	}

}


写回答

1回答

好帮手慕阿莹

2019-07-13

1、同学对本项目理解的是正确的。

2、一般情况下,在同一个浏览器,打开不同的窗口,并不能登录两个账号,如果登录第二个账户的时候,则第一个账户则被踢下去了。并且两个账户不能共用一个session的,当登录的是李四的时候,就会创建一个新的session了。所以也就不会出现同学说的第二种情况了。(同学想想,你可以在同一个浏览器登录两个京东,或者淘宝的账号吗?即使开两个窗口也不行)

3、这个对象的生命周期是从被创建开始就一直存在,直到服务器关闭销毁。

如果我的回答解决了你的疑惑,请采纳!祝学习愉快!


0

0 学习 · 9666 问题

查看课程