cookie实现自动登录
现在很多网站都有为用户保存登陆信息(即保存Cookie)的功能,当用户下一次进入网站时,可以帮助用户自动登陆,使网站显得更加友好。笔者通过研究ACEGI项目的自动登陆源码,编写了一个安全有效的实现两星期自动登陆功能的JAVA工具类,。下面是具体的实现流程和实现代码。
先说一下流程:
1. 保存用户信息阶段:
当 用户登陆网站时,在登陆页面填写完用户名和密码后,如果用户在提交时还选择了“两星期内自动登陆”复选框,那么在后台程序中验证用户名和密码全都正确后, 还要为用户保存这些信息,以便用户下一次可以直接进入网站;如果用户没有勾选“两星期内自动登陆”复选框,则不必为用户保存信息,那么用户在下一次登陆网 站时仍需要填写用户名和密码。
在保存用户信息阶段,主要的工作是对用户的信息进行加密并保存到客户端。加密用户的信息是较为繁琐的,大致上可分为以下几个步聚:
① 得到用户名、经MD5加密后的用户密码、cookie有效时间(本文设置的是两星期,可根据自己需要修改)
② 自定义的一个webKey,这个Key是我们为自己的网站定义的一个字符串常量,这个可根据自己需要随意设置
③ 将上两步得到的四个值得新连接成一个新的字符串,再进行MD5加密,这样就得到了一个MD5明文字符串
④ 将用户名、cookie有效时间、MD5明文字符串使用“:”间隔连接起来,再对这个连接后的新字符串进行Base64编码
⑤ 设置一个cookieName,将cookieName和上一步产生的Base64编码写入到客户端。
2. 读取用户信息:
其实弄明白了保存原理,读取及校验原理就很容易做了。读取和检验可以分为下面几个步骤:
① 根据设置的cookieName,得到cookieValue,如果值为空,就不帮用户进行自动登陆;否则执行读取方法
② 将cookieValue进行Base64解码,将取得的字符串以split(“:”)进行拆分,得到一个String数组cookieValues(此操作与保存阶段的第4步正好相反),这一步将得到三个值:
cookieValues[0] ---- 用户名
cookieValues[1] ---- cookie有效时间
cookieValues[2] ---- MD5明文字符串
③ 判断cookieValues的长度是否为3,如果不为3则进行错误处理。
④ 如果长度等于3,取出第二个,即cookieValues[1],此时将会得到有效时间(long型),将有效时间与服务器系统当前时间比较,如果小于当前时间,则说明cookie过期,进行错误处理。
⑤ 如果cookie没有过期,就取cookieValues[0],这样就可以得到用户名了,然后去数据库按用户名查找用户。
⑥ 如果上一步返回为空,进行错误处理。如果不为空,那么将会得到一个已经封装好用户信息的User实例对象user
⑦ 取出实例对象user的用户名、密码、cookie有效时间(即cookieValues[1])、webKey,然后将四个值连接起来,然后进行MD5加密,这样做也会得到一个MD5明文字符串(此操作与保存阶段的第3步类似)
⑧ 将上一步得到MD5明文与cookieValues[2]进行equals比较,如果是false,进行错误处理;如果是true,则将user对象添加到session中,帮助用户完成自动登陆
web.xml 增加
CookieUtil.java
package com.eportal.util;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import com.eportal.ORM.Cart;
import com.eportal.ORM.Cartselectedmer;
import com.eportal.ORM.Member;
import com.eportal.constants.AppConstants;
import com.eportal.service.CartService;
import com.eportal.service.MemberService;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
public class CookieUtil {
private static MemberService memberService;
private static CartService cartService;
/**
* 增加
* @param name
* @param value
*/
public static void addCookie(String name, String value) {
Cookie cookie = new Cookie(name.trim(), value.trim());
cookie.setMaxAge(AppConstants.COOKIE_DEFAULT_AGE);// 设置为7天
cookie.setPath(AppConstants.COOKIE_DEFAULT_PATH);
ServletActionContext.getResponse().addCookie(cookie);
}
/**
* 修改
* @param c
* @param value
*/
public static void fixCookie(Cookie c, String value) {
c.setValue(value.trim());
c.setMaxAge(AppConstants.COOKIE_DEFAULT_AGE);// 设置为7天
c.setPath(AppConstants.COOKIE_DEFAULT_PATH);
ServletActionContext.getResponse().addCookie(c);
}
public static void editCookie(String name, String value) {
Cookie[] cookies = ServletActionContext.getRequest().getCookies();
if(cookies!=null&&cookies.length>0){
for(Cookie c:cookies){
if(c.getName().equals(name)){
fixCookie(c,value);
break;
}
}
}
}
/**
* 删除
* @param c
*/
public static void deleteCookie(Cookie c){
c.setMaxAge(0);// 设置为0
c.setPath(AppConstants.COOKIE_DEFAULT_PATH);
ServletActionContext.getResponse().addCookie(c);
}
public static void deleteCookie(String cookieName){
Cookie[] cookies = ServletActionContext.getRequest().getCookies();
if(cookies!=null&&cookies.length>0){
for(Cookie c:cookies){
if(c.getName().equals(cookieName)){
deleteCookie(c);
break;
}
}
}
}
/**
* 从cookie中取密文并实现自动登录功能
* @param cValue
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
* @throws UnsupportedEncodingException
*/
public static void readCookieAndAutoLogin(String cValue, HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException, UnsupportedEncodingException {
String cookieValue = cValue;
if (cookieValue == null) {
chain.doFilter(request, response);
return;
}
String cookieValueAfterDecode = new String(Base64.decode(cookieValue),"utf-8");
String[] cookieValues = cookieValueAfterDecode.split(":");
if (cookieValues.length != 2) {
chain.doFilter(request, response);
return;
}
// 取出cookie中的用户名,并到数据库中检查这个用户名
String loginname = cookieValues[0];
// 根据用户名到数据库中检查用户是否存在
memberService = (MemberService)SpringUtil.getBean("memberService");
Member member = memberService.loadByLoginNameOrEmail(loginname);
if (member != null) {
String md5ValueInCookie = cookieValues[1];
String md5ValueByName = MD5.MD5Encode(member.getLoginName() + ":"+ member.getLoginPwd()+ ":" + AppConstants.WEBKEY);
String md5ValueByEmail = MD5.MD5Encode(member.getEmail() + ":"+ member.getLoginPwd()+ ":" + AppConstants.WEBKEY);
// 将结果与Cookie中的MD5码相比较,如果相同,写入Session,自动登录成功,并继续用户请求
if(md5ValueByName.equals(md5ValueInCookie)||md5ValueByEmail.equals(md5ValueInCookie)) {
HttpSession session = request.getSession(true);
session.setAttribute("member", member);
//查询购物车商品数量及未读消息
cartService = (CartService)SpringUtil.getBean("cartService");;
Cart cart = cartService.loadCart(member);
String noticeCount = "";
String cartSize = "";
int size = 0;
if(cart!=null){
List
if (selList != null && !selList.equals("")) {
for (Cartselectedmer cartCount : selList) {
size += cartCount.getNumber();
}
}
}
if (0 cartSize = String.valueOf(size); } else if(size>99){ cartSize = "n"; } int notices = cartService.getNoReadCount(member); if (0 noticeCount = String.valueOf(notices); } else if(notices>99){ noticeCount = "n"; } // 通知数量和购物车商品数量存放到session里 session.setAttribute("cartSize", cartSize); session.setAttribute("noticeCount", noticeCount); } } chain.doFilter(request, response); } } AutoLogonFilter.java 过滤器程序,可在WEB-INF/web.xml中设置过滤规则,本文对过滤规则不作介绍,此程序主要作用是检查用户在上一次登陆时是否保存了Cookie,如果保存了,就处理Cookie信息,并帮助用户自动登陆 本程序主要调用了CookieUtil.java中的读取与自动登陆方法,即readCookieAndLogon方法 package com.eportal.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.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.eportal.ORM.Member; import com.eportal.constants.AppConstants; import com.eportal.util.CookieUtil; /** * Servlet Filter implementation class AutoLogonFilter */ public class AutoLoginFilter implements Filter { /** * Default constructor. */ public AutoLoginFilter() { } /** * @see Filter#destroy() */ public void destroy() { } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; HttpSession session = request.getSession(true); Member member = (Member) session.getAttribute("member"); String url = request.getRequestURI().toString(); // 如果member不为空,说明已经登录,则继续执行用户的请求 if (member != null) { chain.doFilter(request, response); return; } // member为空,说明用户还没有登录,就尝试得到浏览器传送过来的Cookie Cookie[] cookies = request.getCookies(); String cookieValue = null; if(cookies!=null&&cookies.length>0){ for(Cookie c:cookies){ if(c.getName().equals(AppConstants.COOKIENAME_AUTOLOGIN)){ cookieValue = c.getValue(); break; } } } // 如果cookieValue为空,也继续执行用户请求 if (cookieValue == null) { chain.doFilter(request, response); return; } // cookieValue不为空执行自动登录readCookieAndLogon方法 try { CookieUtil.readCookieAndAutoLogin(cookieValue, request, response, chain); } catch (Exception e) { e.printStackTrace(); } } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub } }