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;
        }
    }
  • 相关阅读:
    Codechef之2014FebChallenge
    Codechef之CodeCraft: IIIT Hyderabad
    原创水题
    用图论模型解决dp问题
    [某模拟赛]一道好题
    萌新java入门笔记
    CodeForces 761C 【DP】
    POJ3268【最短路】
    POJ3191【(-2)进制本质】
    POJ3264 【RMQ基础题—ST-线段树】
  • 原文地址:https://www.cnblogs.com/ciaos/p/3611081.html
Copyright © 2011-2022 走看看