Javaweb的session与cookie,实现用户自动登录的完整梳理

  • Post author:
  • Post category:java


这个完整案例只用简单的 Jsp + Ajax + Servlet来完成。

一、登录

略过页面简单的表单验证,直接进入LoginServlet

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//获取表单内容
		String userName = request.getParameter("usn");
		String pwd = request.getParameter("pwd");
		String remember = request.getParameter("remember");
                //获取当前会话的session
		HttpSession session = request.getSession();		
		//执行doLogin并返回登录信息是否正确的结果
		boolean res = userinfobiz.doLogin(userName, pwd);		
		if (res) {
			//结果为真,通过getUserByname方法获取用户信息
			UserInfo user = userinfodao.getUserByName(userName);
			//把用户信息存储到session中
			session.setAttribute("userName", userName);
			session.setAttribute("id", user.getId());
			session.setAttribute("email", user.getEmail());
			session.setAttribute("state", user.getState());
			session.setAttribute("headimageurl", user.getHeadimageurl());
			session.setAttribute("nickname", user.getNickname());
			session.setAttribute("systemtime", user.getSystemtime());
                        //给session设置一个自定义变量,代表已经登录了
			session.setAttribute("loginstate", "userhavinglogin");			
			//新建一个name叫做"SINSESSION"的cookie并把用户ID存到value中
			Cookie cookie = new Cookie("SINSESSION",user.getId());
			//设置作用域,这里设置为根目录以下所有
			cookie.setPath("/");
			//验证表单获得的参数,如果为真设置cookie生命周期为一周,如果为假设置为1天
			if("ture".equals(remember)) {
				cookie.setMaxAge(7*24*60*60);
			}else{
				cookie.setMaxAge(24*60*60);
			}
			//将设置好的cookie保存到客户端的浏览器
			response.addCookie(cookie);
			System.out.println("cookie.age: " + cookie.getMaxAge());
			System.out.println("cookie.name: " + cookie.getName());
			System.out.println("cookie.value: " + cookie.getValue());
		        //判断用户是否为管理员
			String adminname = "sintemple";
			if (userName.equals(adminname)) {
				request.getRequestDispatcher("/page/manage/admin.jsp").forward(request, response);
			} else {
				RequestDispatcher rd = request.getRequestDispatcher("/page/main/logsuc.jsp");
				rd.forward(request, response);
			}
		} else {
			session.invalidate(); 
			response.sendRedirect("/page/main/logero.jsp");
		}
}

二、登录后页面回显用户信息,这里是Ajax载入的Jsp模板

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!-- 如果用户昵称为空显示此段 -->
<c:if test="${sessionScope.nickname == null}">
<li class="nav-item">
	<a href="/page/main/login.jsp" style="color: white; font-size: 2em;">
		<i class="mdi mdi-account-circle"></i>							
	</a>
</li>
<!-- 如果用户昵称不为空显示此段 -->
</c:if>
<c:if test="${sessionScope.nickname != null}">
<li class="nav-item dropdown">
    <a	class="nav-link dropdown-toggle text-muted waves-effect waves-dark p-0"
	href="" data-toggle="dropdown" aria-haspopup="true"
	aria-expanded="false"><img src="${sessionScope.headimageurl}"
		alt="user" class="profile-pic" /></a>
	<div class="dropdown-menu dropdown-menu-right scale-up">
		<ul class="dropdown-user">
			<li>
				<div class="dw-user-box">
					<div class="u-img">
						<img src="${sessionScope.headimageurl}" alt="user">
					</div>
					<div class="u-text">
						<h4 class="m-b-10">${sessionScope.nickname}</h4>
						<p class="text-muted">欢迎您的登录!</p>
						<a href="/page/siner/myprofile.jsp"
							class="btn btn-rounded btn-danger btn-sm">个人信息</a>
					</div>
				</div>
			</li>
			<li role="separator" class="divider"></li>
			<li><a href="/page/siner/myhome.jsp"><i class="ti-user"></i> 我的主页</a></li>
			<li><a href="/page/siner/.myFavorite?classify=gallery&page=1&state=init"><i class="ti-wallet"></i> 我的收藏</a></li>
			<li><a href=""><i class="ti-email"></i> 消息管理 </a></li>
			<li role="separator" class="divider"></li>
			<li><a href=""><i class="ti-settings"></i> 设置 </a></li>
			<li role="separator" class="divider"></li>
			<li><a href=".logoutServlet"><i class="fa fa-power-off"></i> 退出</a></li>
		</ul>
	</div>
</li>
</c:if>

三、这时用户关闭了浏览器,在打开浏览器访问网站时,浏览器会新建一个session,跟关闭客户端之前的session不一样,所以这里要用登录时保存在浏览器里的cookie来验证并自动登录。这里用Ajax指向一个VerifyCookieServlet。

Jsp页面javascript部分

<!-- 引入Ajax文件 -->
<script src="../../js/sin.js"></script>
<!-- 在页面定义全局变量,因为引入的JS文件获取不到sessionScope,但在这里定义一下,就可以取到 -->
<script type="text/javascript">	
	var nickname = '${sessionScope.nickname}';
	var loginstate = '${sessionScope.loginstate}';
</script>

Ajax部分

$(document).ready(function() {
	//获取当前访问页面地址
	var pageurl = window.location.href;	
	//验证如果昵称和session自定义状态都为空时,调用Ajax
	if(nickname == "" && loginstate == "") {
		$.ajax({
			//指向验证cookie的方法
			url:".verifyCookieState",
			success:function() {
				//验证之后载入用户输入的访问页面
				window.location.href = pageurl;
				//载入登录显示区域,这里在URL后加入一个当前时间,因为ie对Ajax的调用模板的URL有一个缓存机制,如果URL不变会使用缓存的记录
				var url = '/page/include/userlog.jsp?time=' + new Date().getTime();
				$('.userlog').load(url);				
			}	
		});	
	} else {
		//如果昵称不为空且state里存了“userhavedlogin”,代表用户已登录不需要验证cookie;或者昵称为空state里存了"visitnoneedlogin",代表用户为游客,不需要验证cookie
		var url = '/page/include/userlog.jsp?time=' + new Date().getTime();
		$('.userlog').load(url);
	}
});

Servlet验证部分

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	//获取session
	HttpSession session = request.getSession();
	//获取cookie
	Cookie[] cookies = request.getCookies();
	if (cookies != null) {
		//遍历从客户端获取的cookie
		int lenght = cookies.length;
		for (int i = 0; i < lenght; i++) {
			Cookie c = cookies[i];
			System.out.println("name:" + c.getName() + " value:" + c.getValue() + " age:" + c.getMaxAge());
			//如果客户端的某个cookie中的name等于之前设置的"SINSESSION",说明该浏览器有本站设置的cookie
			if ("SINSESSION".contentEquals(c.getName())) {
				//通过cookie之前存储进去的用户ID,走DAO层,取出用户信息
				user = userdao.getUserById(c.getValue());
				// 把用户信息存储到当前会话的session中
				session.setAttribute("userName", user.getUserName());
				session.setAttribute("id", user.getId());
				session.setAttribute("email", user.getEmail());
				session.setAttribute("state", user.getState());
				session.setAttribute("headimageurl", user.getHeadimageurl());
				session.setAttribute("nickname", user.getNickname());
				session.setAttribute("systemtime", user.getSystemtime());
				//给session设置一个自定义变量,代表该用户已经登录了
				session.setAttribute("loginstate", "userhavedlogin");
				System.out.println("老用户回访: " + session.getAttribute("nickname"));
				break;
			} else if (i == lenght - 1 && !"SINSESSION".contentEquals(c.getName())) {
				//如果一直遍历到最后一个cookie且仍不是本站设置的cookiename,就给登录状态设置为游客暂且不需要登录
				session.setAttribute("loginstate", "visitnoneedlogin");
			}
		}
	}		
}

四、注销部分

public void doPost(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
	//获取当前会话的session
	HttpSession session = request.getSession();
	//取得登录的用户名   
        String userName = (String) session.getAttribute("userName");
        System.out.println(userName+" is out");
        //销毁session
        session.invalidate();
        //给名为SINSESSION的cookie复写,将cookie的生命周期设置为0,相当于从客户端销毁了cookie
        Cookie cookie = new Cookie("SINSESSION","");
	cookie.setPath("/");
	cookie.setMaxAge(0);
	//把复写的cookie返回给客户端
	response.addCookie(cookie);    
	response.sendRedirect("/");
}

五、这样完成了验证登录的整体结构。注意的几个点:

1. Ajax调用模板的URL在IE下会有缓存影响,要在每次调用时改变URL,在地址结尾加随机参数。

2. action层处理完cookie验证后,一定不要忘了在返回Ajax成功的方法里,再次载入访问页面的地址,因为如果访问的页面是非用户页面,看不出问题,如果是用户有关的页面,比如用户收藏页面,会发现页面无用户数据内容,因为如果访问地址的数据请求和Ajax的验证同步请求,session中的用户ID肯定是空的,取不到用户数据,所以需要弄个拦截器先把访问地址的请求拦截下来,待cookie验证完以后,带着登录后的session再次载入访问地址。

3. 将Ajax的脚本放入js文件中,就可以方便每个页面引用,不用挨个粘贴一大段,但是引入的js文件无法获取sessionScope,所以要在所有页面,先定义好要所需内容的全局变量。



版权声明:本文为chenlkissmm原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。