zoukankan      html  css  js  c++  java
  • 通过邮箱找回密码简单实现

    基本步骤:

    1,用户访问网站公开的页面,输入注册邮箱,点击"发送找回密码邮件"按钮

    2,服务器检测该邮箱正确性及是否有注册,如果已注册,生成一个时间戳+邮箱名的随机数加密后使用Javamail类发送邮件

    3,用户登录自己的邮箱点击回调url

    4,服务器检测回调url中参数时效性和正确性,如果正确则进入重置密码环节。

    依赖包:

    mysql-connector-java-5.0.8-bin.jar

    java-mail-1.4.jar

    源代码如下:

    A,入口(注册/forgot到AccountHelperServlet上面)

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.0" 
        xmlns="http://java.sun.com/xml/ns/javaee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
      <display-name></display-name>    
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
        <servlet>
            <servlet-name>ForgotPwdServlet</servlet-name>
            <servlet-class>com.mycompany.account.AccountHelperServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>ForgotPwdServlet</servlet-name>
            <url-pattern>/forgot</url-pattern>
        </servlet-mapping>
    </web-app>

    B,Servlet业务逻辑(主要是发送邮件)

    package com.mycompany.account;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.sql.SQLException;
    
    import javax.servlet.RequestDispatcher;
    import javax.servlet.Servlet;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class AccountHelperServlet extends HttpServlet implements Servlet {
    
        /**
         * 
         */
        private static final long serialVersionUID = -643722721720417036L;
        
        private static final int validtime = 1000 * 60 * 10; // 10 minutes
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            // TODO Auto-generated method stub
            
            String action = req.getParameter("action");
            
            //
            // show forget password page
            //
            if(action == null){
                RequestDispatcher rd = req.getRequestDispatcher("/forgot.jsp");  
                rd.forward(req, resp);  
                return;
            }
            //
            // show reset password page
            //
            else if(action.equals("reset")){
                String token = req.getParameter("token");
                try{
                    EncryptDecryptData des = new EncryptDecryptData();
                    String rawtoken = null;
                    try{
                        rawtoken = des.decrypt(token);
                    }catch(Exception ex){
                        resp.sendError(400,"bad request");
                        return;
                    }
                    
                    long currTimeMillis = System.currentTimeMillis();
                    long prevTimeMillis = Long.parseLong(rawtoken.split(" ")[0]);
                    if(currTimeMillis - prevTimeMillis > validtime){
                        resp.sendError(400,"bad request");
                        return;
                    }
                    
                    req.setAttribute("token", token);  
                    RequestDispatcher rd = req.getRequestDispatcher("/reset.jsp");  
                    rd.forward(req, resp);
                    return;
                }
                catch(Exception ex){
                    resp.sendError(500,"internal server error");
                    return;
                }
            }
            else{
                resp.sendError(400,"bad request");
                return;
            }    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            
            String action = req.getParameter("action");
            //
            // send mail action
            //
            if(action.equals("sendmail")){
                String mailAddress = req.getParameter("mailaddress");
                String ret = null;
                try {
                    ret = AccountHelperUtils.SelectMail(mailAddress);
                    
                } catch (SQLException e) {
                    resp.sendError(500,"internal server error");
                    return;
                }
                if(ret == null){
                    resp.sendError(400,"bad request");
                    return;
                }
                
                String rawtoken = System.currentTimeMillis() + " " + ret;
                String token = "";
                try{
                    EncryptDecryptData des = new EncryptDecryptData();// 使用默认密钥
                    token = des.encrypt(rawtoken);
                }
                catch(Exception ex){
                    resp.sendError(500,"internal server error");
                    return;
                }
                
                String genurl = "http://www.mycompany.com/forgot?action=reset&token="+token;
                String mailContent = "<div>" +
                        "<div>亲爱的mycompany用户</div>" +
                        "<div>您已经在mycompany申请了找回密码,请点击下面链接,重新设置您的密码:</div>" +
                        "<div><a href=""+genurl+"">"+genurl+"</a></div>" + 
                        "<div>此信是由mycompany系统发出,系统不接受回信,请勿直接回复。</div>" +
                        "<div>致礼!</div>" +
                        "</div>";
                MailHelperUtils.sendEmail("mycompany@mycompany.com", "mailpassword", new String[]{mailAddress}, "请重置您的mycompany账号密码", mailContent, null, "text/html", "UTF8");
                
                PrintWriter out=resp.getWriter();
                out.println("mail sent, please login mail to check!");
                out.close();
                return;
            }
            //
            // reset password action
            //
            else if(action.equals("resetpwd")){
                String newpwd = req.getParameter("newpwd");
                String token = req.getParameter("token");
                try{
                    EncryptDecryptData des = new EncryptDecryptData();
                    String rawtoken = null;
                    try{
                        rawtoken = des.decrypt(token);
                    }catch(Exception ex){
                        resp.sendError(400,"bad request");
                        return;
                    }
                    long currTimeMillis = System.currentTimeMillis();
                    long prevTimeMillis = Long.parseLong(rawtoken.split(" ")[0]);
                    if(currTimeMillis - prevTimeMillis > validtime){
                        resp.sendError(400,"bad request");
                        return;
                    }
                    
                    String mailAddress = rawtoken.split(" ")[1];
                    boolean ret = AccountHelperUtils.UpdatePwd(mailAddress, newpwd);
                    if(ret){
                        PrintWriter out=resp.getWriter();
                        out.println("password reset,please relogin");
                        out.close();
                        return;
                    }else{
                        resp.sendError(500,"internal server error");
                        return;
                    }
                }
                catch(Exception ex){
                    resp.sendError(500,"internal server error");
                    return;
                }
                
            } else{
                resp.sendError(400,"bad request");
                return;
            }
        }
    }

    forgot.jsp

    <%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <title>Forgot Password</title>
      </head>
      
      <body>
          <form action="/forgot?action=sendmail" method="post">
              <input type="text" name="mailaddress" />
              <input type="submit" value="send mail" />
          </form>
      </body>
    </html>

    reset.jsp

    <%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <title>find password demo</title>
      </head>
      
      <body>
           <form action="/forgot?action=resetpwd" method="post">
                   <input type="hidden" name="token" value="<%=(String)request.getAttribute("token")%>" />
                   <input type="text" name="newpwd" />
                   <input type="submit" value="update password" />
           </form>
      </body>
    </html>

    C,工具类

    a,发送邮件工具(通过设置smtp发送邮件)

    package com.mycompany.mail;
    
    import java.io.File;
    import java.util.Date;
    import java.util.Properties;
    
    import javax.activation.DataHandler;
    import javax.activation.FileDataSource;
    import javax.mail.Authenticator;
    import javax.mail.Message;
    import javax.mail.Multipart;
    import javax.mail.PasswordAuthentication;
    import javax.mail.Session;
    import javax.mail.Transport;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeBodyPart;
    import javax.mail.internet.MimeMessage;
    import javax.mail.internet.MimeMultipart;
    import javax.mail.internet.MimeUtility;
    
    public class MailHelperUtils {
        
        public static void sendEmail(final String sender,final String password,String[] receivers, String title, String mailContent, File[] attachements, String mimetype, String charset) {
            Properties props = new Properties();
            //设置smtp服务器地址
            //这里使用QQ邮箱,记得关闭独立密码保护功能和在邮箱中设置POP3/IMAP/SMTP服务
            props.put("mail.smtp.host", "smtp.exmail.qq.com");
            //需要验证
            props.put("mail.smtp.auth", "true");
            //创建验证器
            Authenticator authenticator = new Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(sender, password);
                }
            };
            //使用Properties创建Session
            Session session = Session.getDefaultInstance(props, authenticator);
            //Set the debug setting for this Session
            //session.setDebug(true);
            try {
                //使用session创建MIME类型的消息
                MimeMessage mimeMessage = new MimeMessage(session);
                //设置发件人邮件
                mimeMessage.setFrom(new InternetAddress(sender));
                //获取所有收件人邮箱地址
                InternetAddress[] receiver = new InternetAddress[receivers.length];
                for (int i=0; i<receivers.length; i++) {
                    receiver[i] = new InternetAddress(receivers[i]);
                }
                //设置收件人邮件
                mimeMessage.setRecipients(Message.RecipientType.TO, receiver);
                //设置标题
                mimeMessage.setSubject(title, charset);
                //设置邮件发送时间
                //SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                //mimeMessage.setSentDate(format.parse("2011-12-1"));
                mimeMessage.setSentDate(new Date());
                //创建附件
                Multipart multipart = new MimeMultipart();
                //创建邮件内容
                MimeBodyPart body = new MimeBodyPart();
                //设置邮件内容
                body.setContent(mailContent, (mimetype!=null && !"".equals(mimetype) ? mimetype : "text/plain")+ ";charset="+ charset);
                multipart.addBodyPart(body);//发件内容
                //设置附件
                if(attachements!=null){
                    for (File attachement : attachements) {
                        MimeBodyPart attache = new MimeBodyPart();
                        attache.setDataHandler(new DataHandler(new FileDataSource(attachement)));
                        String fileName = getLastName(attachement.getName());
                        attache.setFileName(MimeUtility.encodeText(fileName, charset, null));
                        multipart.addBodyPart(attache);
                    }
                }
                //设置邮件内容(使用Multipart方式)
                mimeMessage.setContent(multipart);
                //发送邮件
                Transport.send(mimeMessage);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        private static String getLastName(String fileName) {
            int pos = fileName.lastIndexOf("\");
            if (pos > -1) {
                fileName = fileName.substring(pos + 1);
            }
            pos = fileName.lastIndexOf("/");
            if (pos > -1) {
                fileName = fileName.substring(pos + 1);
            }
            return fileName;
        }
    }

    b,操作数据库工具(检测邮件地址正确性及更新密码)

    package com.mycompany.mail;
    import java.sql.*;
    
    public class AccountHelperUtils {
        
        final private static String MysqlHost = "127.0.0.1";
        final private static String TableName = "account";
        final private static String DbName = "testdb";
        final private static String UserName = "username";
        final private static String PassWord = "password";
        
        static Connection conn;  
        
        public static String SelectMail(String mailAddress) throws SQLException{
            String userMail = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try{
                conn = getConnection();
                
                String sql = "select * from "+TableName+" where name = ?";
                ps = conn.prepareStatement(sql);
                ps.setString(1,    mailAddress);
                rs = ps.executeQuery();
                
                while(rs.next()){
                    userMail = rs.getString("name");
                    break;
                }
            }catch(Exception ex){
                return null;
            }finally{
                if(rs!=null){rs.close();}
                if(ps!=null){ps.close();}
                if(conn!=null){conn.close();conn = null;};
            }
            return userMail;
        }
        
        public static Boolean UpdatePwd(String mailAddress, String newpwd) throws SQLException{
            boolean ret = true;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try{
                conn = getConnection();
                
                String sql = "update "+TableName+" set pwd = ? where name = ?";
                ps = conn.prepareStatement(sql);
                ps.setString(1,    newpwd);
                ps.setString(2,    mailAddress);
                ps.executeUpdate();
                
            }catch(Exception ex){
                ret = false;
            }finally{
                if(rs!=null){rs.close();}
                if(ps!=null){ps.close();}
                if(conn!=null){conn.close();conn = null;};
            }
            return ret;
        }
        
        private static Connection getConnection() throws Exception {
            Connection con = null;
            try {  
                Class.forName("com.mysql.jdbc.Driver");
                  
                con = DriverManager.getConnection(
                        "jdbc:mysql://"+MysqlHost+"/"+DbName, UserName, PassWord);
                  
            } catch (Exception e) {  
                throw e;
            }  
            return con;
        }
    }

    c,des加密解密工具类

    package com.mycompany.mail;
    
    import java.security.Key;
    import javax.crypto.Cipher;
    /**
     * DES加密和解密工具,可以对字符串进行加密和解密操作  。 
     */
    public class EncryptDecryptData {
        /**
         * 默认构造方法,使用默认密钥
         */
        public EncryptDecryptData() throws Exception {
            this(strDefaultKey);
        }
        /**
         * 指定密钥构造方法
         * @param strKey  指定的密钥
         * @throws Exception
         */
        public EncryptDecryptData(String strKey) throws Exception {
            // Security.addProvider(new com.sun.crypto.provider.SunJCE());
            Key key = getKey(strKey.getBytes());
            encryptCipher = Cipher.getInstance("DES");
            encryptCipher.init(Cipher.ENCRYPT_MODE, key);
            decryptCipher = Cipher.getInstance("DES");
            decryptCipher.init(Cipher.DECRYPT_MODE, key);
        }
        /** 字符串默认键值 */
        private static String strDefaultKey = "mysecretkey";
        /** 加密工具 */
        private Cipher encryptCipher = null;
        /** 解密工具 */
        private Cipher decryptCipher = null;
        /**
         * 将byte数组转换为表示16进制值的字符串, 如:byte[]{8,18}转换为:0813, 和public static byte[]
         * hexStr2ByteArr(String strIn) 互为可逆的转换过程
         * @param arrB  需要转换的byte数组
         * @return 转换后的字符串
         * @throws Exception 本方法不处理任何异常,所有异常全部抛出
         */
        public static String byteArr2HexStr(byte[] arrB) throws Exception {
            int iLen = arrB.length;
            // 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
            StringBuffer sb = new StringBuffer(iLen * 2);
            for (int i = 0; i < iLen; i++) {
                int intTmp = arrB[i];
                // 把负数转换为正数
                while (intTmp < 0) {
                    intTmp = intTmp + 256;
                }
                // 小于0F的数需要在前面补0
                if (intTmp < 16) {
                    sb.append("0");
                }
                sb.append(Integer.toString(intTmp, 16));
            }
            return sb.toString();
        }
        /**
         * 将表示16进制值的字符串转换为byte数组, 和public static String byteArr2HexStr(byte[] arrB)
         * 互为可逆的转换过程
         * @param strIn 需要转换的字符串
         * @return 转换后的byte数组
         */
        public static byte[] hexStr2ByteArr(String strIn) throws Exception {
            byte[] arrB = strIn.getBytes();
            int iLen = arrB.length;
            // 两个字符表示一个字节,所以字节数组长度是字符串长度除以2
            byte[] arrOut = new byte[iLen / 2];
            for (int i = 0; i < iLen; i = i + 2) {
                String strTmp = new String(arrB, i, 2);
                arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
            }
            return arrOut;
        }
        /**
         * 加密字节数组
         * @param arrB  需加密的字节数组
         * @return 加密后的字节数组
         */
        public byte[] encrypt(byte[] arrB) throws Exception {
            return encryptCipher.doFinal(arrB);
        }
        /**
         * 加密字符串
         * @param strIn  需加密的字符串
         * @return 加密后的字符串
         */
        public String encrypt(String strIn) throws Exception {
            return byteArr2HexStr(encrypt(strIn.getBytes()));
        }
        /**
         * 解密字节数组
         * @param arrB  需解密的字节数组
         * @return 解密后的字节数组
         */
        public byte[] decrypt(byte[] arrB) throws Exception {
            return decryptCipher.doFinal(arrB);
        }
        /**
         * 解密字符串
         * @param strIn  需解密的字符串
         * @return 解密后的字符串
         */
        public String decrypt(String strIn) throws Exception {
            return new String(decrypt(hexStr2ByteArr(strIn)));
        }
        /**
         * 从指定字符串生成密钥,密钥所需的字节数组长度为8位 不足8位时后面补0,超出8位只取前8位
         * @param arrBTmp  构成该字符串的字节数组
         * @return 生成的密钥
         */
        private Key getKey(byte[] arrBTmp) throws Exception {
            // 创建一个空的8位字节数组(默认值为0)
            byte[] arrB = new byte[8];
            // 将原始字节数组转换为8位
            for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
                arrB[i] = arrBTmp[i];
            }
            // 生成密钥
            Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES");
            return key;
        }
    }
  • 相关阅读:
    R语言:提取路径中的文件名字符串(basename函数)
    课程一(Neural Networks and Deep Learning),第三周(Shallow neural networks)—— 0、学习目标
    numpy.squeeze()的用法
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 4、Logistic Regression with a Neural Network mindset
    Python numpy 中 keepdims 的含义
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 3、Python Basics with numpy (optional)
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 2、编程作业常见问题与答案(Programming Assignment FAQ)
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 0、学习目标
    课程一(Neural Networks and Deep Learning),第一周(Introduction to Deep Learning)—— 0、学习目标
    windows系统numpy的下载与安装教程
  • 原文地址:https://www.cnblogs.com/ciaos/p/3611081.html
Copyright © 2011-2022 走看看