1。http://www.family168.com/tutorial/jsp/html/jsp-ch-07.html#jsp-ch-07-02
2。
安全有效的实现两星期内自动登陆功能
现在很多网站都有为用户保存登陆信息(即保存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中,帮助用户完成自动登陆
完整的代码,用途请参见注释
CookieUtil.java
处理cookie的工具类,包括读取,保存,清除三个主要方法。
下面的是对CookieUtil工具类各方法的调用演示:
User.java
封装用户信息的JavaBean对象模型
package com.itcast.bean;
public class User { private int id;
private String userName;
private String password;
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public int getId() { return id; }
public void setId(int id) { this.id = id; } } |
AutoLogonFilter.java
过滤器程序,可在WEB-INF/web.xml中设置过滤规则,本文对过滤规则不作介绍,此程序主要作用是检查用户在上一次登陆时是否保存了Cookie,如果保存了,就处理Cookie信息,并帮助用户自动登陆
本程序主要调用了CookieUtil.java中的读取与自动登陆方法,即readCookieAndLogon方法
package cn.itcast.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 cn.itcast bean.User; import cn.itcast.util.CookieUtil;
public class AutoLogonFilter implements Filter {
public void destroy() { }
//保存cookie时的cookieName,与CookieUtil.java中的设置相同 private final static String cookieDomainName = “cn.itcast”;
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); User user = (User)session.getAttribute("user");
//如果封装的user不为空,说明已经登陆,则继续执行用户的请求.下面的就不处理了 if(user!=null){ chain.doFilter(request,response); return; }
//user为空,说明用户还没有登陆,就尝试得到浏览器传送过来的Cookie Cookie cookies[] = request.getCookies(); String cookieValue = null; if(cookies!=null){ for(int i=0;i if (cookieDomainName.equals(cookies[i].getName())) { cookieValue = cookies[i].getValue(); break; } } }
//如果cookieValue为空,也继续执行用户请求 if(cookieValue==null){ chain.doFilter(request,response); return; }
//cookieValue不为空执行下面的方法,调用CookieUtil.java中的readCookieAndLogon方法 try{ CookieUtil.readCookieAndLogon(cookieValue, request, response, chain); }catch(Exception e){ e.printStackTrace(); } }
public void init(FilterConfig arg0) throws ServletException { } } |
CheckLogonServlet.java
验证用户登陆信息的Servlet,此程序调用了CookieUtil.java中的saveCookie方法
UserDAO.java与DaoImplFactory.java属于持久层相关的程序,这里就不贴出来了,读者可根据自己需要选择不同的持久层框架,在本程序中只要实现查询用户的功能就可以了