Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 468|回复: 0

[jsp学习]安全的实现两星期内自动登陆功能

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-2 04:41:10 | 显示全部楼层 |阅读模式
    现在很多网站都有为用户保存登陆信息(即保存Cookie)的功能,当用户下一次进入网站时,可以帮助用户自动登陆,使网站显得更加友好。笔者通过研究ACEGI项目的自动登陆源码,编写了一个安全有效的实现两星期自动登陆功能的java工具类,在此要感谢传智播客公司教学总监张孝祥老师向笔者推荐了ACEGI项目。下面是具体的实现流程和实现代码。 先说一下流程:
           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.getName())) {                                           cookieValue = cookies.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中的MD
          
            5
            码
            相比较,如果相同,写入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组合字符串的MD
          
            5
            码
            的字符串----------------------------------------------------------------------------               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 & 0xf0) >> 4, 16));                             sb.append(Character.forDigit(buffer & 0x
          
            0f
            , 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.getName())) {                                    cookieValue = cookies.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属于持久层相关的程序,这里就不贴出来了,读者可根据自己需要选择不同的持久层框架,在本程序中只要实现查询用户的功能就可以了  
      
       
       
      

      
      
       
       

         
       

         
       
      
    复制代码
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-27 02:11 , Processed in 0.313418 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表