`

cook的使用(两星期自动登录)

阅读更多
写道
导读:
  现在很多网站都有为用户保存登陆信息(即保存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的工具类,包括读取,保存,清除三个主要方法。
  
  package cn.itcast.util;
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.io.UnsupportedEncodingException;
  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 java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import cn.itcast.bean.User;
  import cn.itcast.dao.UserDAO;
  import cn.itcast.factory.DaoImplFactory;
  import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
  /*
  * 2007.09.21 by lyhapple
  * */
  public class CookieUtil {
  //保存cookie时的cookieName
  private final static String cookieDomainName = “cn.itcast”;
  //加密cookie时的网站自定码
  private final static String webKey = “itcast”;
  //设置cookie有效期是两个星期,根据需要自定义
  private final static long cookieMaxAge = 60 * 60 * 24 * 7 * 2;
  //保存Cookie到客户端--------------------------------------------------------------------------------------------------------
  //在CheckLogonServlet.java中被调用
  //传递进来的user对象中封装了在登陆时填写的用户名与密码
  public static void saveCookie(User user, HttpServletResponse response) {
  //cookie的有效期
  long validTime = System.currentTimeMillis() + (cookieMaxAge * 1000);
  //MD5加密用户详细信息
  String cookieValueWithMd5 =getMD5(user.getUserName() + ":" + user.getPassword()+ ":" + validTime + ":" + webKey);
  //将要被保存的完整的Cookie值
  String cookieValue = user.getUserName() + ":" + validTime + ":" + cookieValueWithMd5;
  //再一次对Cookie的值进行BASE64编码
  String cookieValueBase64 = new String(Base64.encode(cookieValue.getBytes()));
  //开始保存Cookie
  Cookie cookie = new Cookie(cookieDomainName, cookieValueBase64);
  //存两年(这个值应该大于或等于validTime)
  cookie.setMaxAge(60 * 60 * 24 * 365 * 2);
  //cookie有效路径是网站根目录
  cookie.setPath("/");
  //向客户端写入
  response.addCookie(cookie);
  }
  //读取Cookie,自动完成登陆操作--------------------------------------------------------------------------------------------
  //在Filter程序中调用该方法,见AutoLogonFilter.java
  public static void readCookieAndLogon(HttpServletRequest request, HttpServletResponse response,
  FilterChain chain) throws IOException, ServletException,UnsupportedEncodingException{
  //根据cookieName取cookieValue
  Cookie cookies[] = request.getCookies();
  String cookieValue = null;
  if(cookies!=null){
  for(int i=0; i<cookies.length; i++){
  if (cookieDomainName.equals(cookies[i].getName())) {
  cookieValue = cookies[i].getValue();
  break;
  }
  }
  }
  //如果cookieValue为空,返回,
  if(cookieValue==null){
  return;
  }
  //如果cookieValue不为空,才执行下面的代码
  //先得到的CookieValue进行Base64解码
  String cookieValueAfterDecode = new String (Base64.decode(cookieValue),"utf-8");
  //对解码后的值进行分拆,得到一个数组,如果数组长度不为3,就是非法登陆
  String cookieValues[] = cookieValueAfterDecode.split(":");
  if(cookieValues.length!=3){
  response.setContentType("text/html; charset=utf-8");
  PrintWriter out = response.getWriter();
  out.println("你正在用非正常方式进入本站...");
  out.close();
  return;
  }
  //判断是否在有效期内,过期就删除Cookie
  long validTimeInCookie = new Long(cookieValues[1]);
  if(validTimeInCookie < System.currentTimeMillis()){
  //删除Cookie
  clearCookie(response);
  response.setContentType("text/html; charset=utf-8");
  PrintWriter out = response.getWriter();
  out.println("<a href=’logon.jsp’>你的Cookie已经失效,请重新登陆</a>");
  out.close();
  return;
  }
  //取出cookie中的用户名,并到数据库中检查这个用户名,
  String username = cookieValues[0];
  //根据用户名到数据库中检查用户是否存在
  UserDAO ud = DaoImplFactory.getInstance();
  User user = ud.selectUserByUsername(username);
  //如果user返回不为空,就取出密码,使用用户名+密码+有效时间+ webSiteKey进行MD5加密
  if(user!=null){
  String md5ValueInCookie = cookieValues[2];
  String md5ValueFromUser =getMD5(user.getUserName() + ":" + user.getPassword()+ ":" + validTimeInCookie + ":" + webKey);
  //将结果与Cookie中的MD5码相比较,如果相同,写入Session,自动登陆成功,并继续用户请求
  if(md5ValueFromUser.equals(md5ValueInCookie)){
  HttpSession session = request.getSession(true);
  session.setAttribute("user", user);
  chain.doFilter(request, response);
  }
  }else{
  //返回为空执行
  response.setContentType("text/html; charset=utf-8");
  PrintWriter out = response.getWriter();
  out.println("cookie验证错误!");
  out.close();
  return;
  }
  }
  //用户注销时,清除Cookie,在需要时可随时调用------------------------------------------------------------
  public static void clearCookie( HttpServletResponse response){
  Cookie cookie = new Cookie(cookieDomainName, null);
  cookie.setMaxAge(0);
  cookie.setPath("/");
  response.addCookie(cookie);
  }
  //获取Cookie组合字符串的MD5码的字符串----------------------------------------------------------------------------
  public static String getMD5(String value) {
  String result = null;
  try{
  byte[] valueByte = value.getBytes();
  MessageDigest md = MessageDigest.getInstance("MD5");
  md.update(valueByte);
  result = toHex(md.digest());
  } catch (NoSuchAlgorithmException e2){
  e1.printStackTrace();
  }
  return result;
  }
  //将传递进来的字节数组转换成十六进制的字符串形式并返回
  private static String toHex(byte[] buffer){
  StringBuffer sb = new StringBuffer(buffer.length * 2);
  for (int i = 0; i < buffer.length; i++){
  sb.append(Character.forDigit((buffer[i] &0xf0) >>4, 16));
  sb.append(Character.forDigit(buffer[i] &0x0f, 16));
  }
  return sb.toString();
  }
  }
  下面的是对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<cookies.length; 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方法
  package cn.itcast.servlet;
  /*
  * update 2007.09.23 by lyhapple
  * 检查用户登陆
  * */
  import java.io.IOException;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  import cn.itcast.bean.User;
  import cn.itcast.dao.UserDAO;
  import cn.itcast.factory.DaoImplFactory;
  import cn.itcast.util.CookieUtil;
  public class CheckLogonServlet extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
  doPost(request, response);
  }
  public void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
  request.setCharacterEncoding("utf-8");
  String username = request.getParameter("username").trim();
  String password = CookieUtil.getMD5(request.getParameter("password"));
  String remeberMe = request.getParameter("remeberMe");
  HttpSession session = request.getSession(false);
  // 将接收到的用户名传递到UserDao的checkUser方法中,检查用户
  // 返回一个User类型的对象
  UserDAO ud = DaoImplFactory.getInstance();
  User user = ud.selectUserByUsername(username);
  if (user == null) {
  request.setAttribute("checkUserError","<a href='register.jsp'><font color=red>用户名不存在,请先注册</font></a>");
  request.getRequestDispatcher("index.jsp").forward(request, response);
  return;
  }
  if(!password.equals(user.getPassword())){
  request.setAttribute("checkPasswordError","<font color=red>密码输入错误,请重新输入</font>");
  request.getRequestDispatcher("index.jsp").forward(request, response);
  return;
  }
  //保存Cookie,这里调用了CookieUtil.java中的saveCookie方法,将上面的user对象作为参数传递
  if ("on".equals(remeberMe)) {
  CookieUtil.saveCookie(user, response);
  }
  //在Session中保存用户信息,并转向用户的个人信息页面
  session.setAttribute("user", user);
  request.getRequestDispatcher("User/userInfo.jsp").forward(request,response);
  }
  }
  UserDAO.java与DaoImplFactory.java属于持久层相关的程序,这里就不贴出来了,读者可根据自己需要选择不同的持久层框架,在本程序中只要实现查询用户的功能就可以了

 

分享到:
评论

相关推荐

    KMplayer cook.dll

    2. **手动指定解码器**:在播放文件时,选择使用特定的解码器进行解码,而不是让播放器自动选择。 3. **使用解码器管理工具**:如“K-Lite Codec Pack”等第三方解码器包,它们可以更好地管理系统的解码器,避免...

    百度账号COOKIE登录浏览器

    当用户下次访问同一网站时,浏览器会发送这些COOKIE给服务器,从而识别用户身份,实现自动登录和其他个性化设置。百度账号的COOKIE包含了用户登录状态的信息,因此导入该COOKIE到特定浏览器后,用户无需输入账号密码...

    johnson-cook.zip_drawbbc_johnson cook_johnson cook umat_johnson-

    约翰逊-库克(Johnson-Cook)模型是一种广泛应用于金属材料塑性变形模拟的本构关系模型,尤其在焊接、冲击、热成形等领域的数值模拟中占据重要地位。该模型考虑了应变、应变速率、温度以及加载历史等因素对材料应力-...

    COOK

    关于"COOK"这个特定的字体,可能需要进一步的信息才能详细讨论其特点、使用场景以及与其他字体的区别。如果它是一个应用,那么可能会包含用户友好的界面设计、食谱分类、搜索功能以及社交分享等特性,帮助用户管理和...

    【低代码平台】商城可视化搭建平台 -Mall-Cook

    【低代码平台】商城可视化搭建平台 - Mall-Cook 是一种创新的电商解决方案,它允许开发者和非技术人员通过图形用户界面快速构建和定制电子商务网站。这个平台的核心特点在于其可视化构建功能,大大降低了商城开发的...

    R programming cook book

    本文内容主要涉及了R编程cook book这本书的介绍,包括其出版背景、编辑团队以及出版的相关书籍系列。下面将详细解读这些知识点。 首先,R programming cook book这本书主要是用于引导R编程初学者。R语言是一种广泛...

    Johnson Cook_VUMAT.zip_ABAQUS_ABAQUS vumat_abaqus-vumat_johnson

    Johnson Cook model,abaqus VUMAT

    johnson cook-vumat-temp.rar_cook_johnson cook vumat_johnson-cook

    标题 "johnson cook-vumat-temp.rar_cook_johnson cook vumat_johnson-cook" 暗示了我们正在讨论一个与Johnson-Cook模型相关的VUMAT(Von Mises Updated Material Algorithm)文件。VUMAT是ABAQUS等有限元软件中的一...

    《PythonCook》

    在数据结构和算法方面,书中介绍了如何进行序列解压赋值给多个变量、保留最后N个元素、查找最大或最小的N个元素、实现优先级队列、字典中键映射多个值、字典排序、字典的运算、查找两字典的相同点、删除序列相同元素...

    cook文档存储

    ### IT知识点:Cook文档存储与会话管理技术详解 #### 一、会话技术概览 在探讨具体的会话管理技术之前,我们首先需要理解何为会话技术及其在编程中的重要作用。会话技术,简单而言,指的是在客户端与服务器之间...

    《Combinatorial Optimization》Cook, Cunningham, Pulleyblank, Schrijver

    《Combinatorial Optimization》Cook, Cunningham, Pulleyblank, Schrijver

    JUnit A Cook’s Tour

    《JUnit A Cook’s Tour》是一本深入探讨Java单元测试框架JUnit的指南,旨在帮助开发者熟练掌握这个强大的工具。JUnit是Java开发中不可或缺的部分,它提供了一种系统化的方法来编写和运行可重复的自动化测试,确保...

    asp.net 2.0 .cook

    ASP.NET 2.0 .Cook 是一份专门针对ASP.NET 2.0开发的学习资源,它提供了丰富的实践示例和技巧,旨在帮助开发者更好地理解和应用这一技术。这份文档可能包括了从基础概念到高级特性的全面讲解,对于初学者和有经验的...

    cookie自动登陆

    在IT领域,尤其是在Web开发中,"Cookie自动登录"是一个常见的功能,它极大地提升了用户体验,让用户在访问网站时能够快速便捷地登录。这个功能主要基于HTTP协议中的Cookie机制实现,结合.NET框架,我们可以构建出...

    mysql 8 cook book

    本书的作者是Karthik Appigatla,他通过本书分享了自己在数据库管理和性能优化方面的丰富经验,帮助读者快速掌握如何使用 MySQL 8 解决各种数据库相关问题。 在学习 MySQL 8 Cookbook 时,读者可以期待获得以下知识...

    关于集群 cook 覆盖问题 及解决方法

    【关于集群 cook 覆盖问题及解决方法】 在分布式系统和集群环境中,尤其是在使用WebLogic这样的企业级应用服务器时,跨域Session管理是常见的挑战。WebLogic Server中,两个不同域的应用之间可能存在Session冲突,...

    scikit-learn cook

    1. 机器学习(Machine Learning)与深度学习(Deep Learning)是数据科学(Data Science)的重要组成部分,需要使用到数学(Maths)知识。 2. 对于希望从事机器学习或深度学习工作的人来说,数学知识非常重要,尤其...

Global site tag (gtag.js) - Google Analytics