Java實現郵箱找回密碼

經過郵件找回密碼功能的實現java

一、最近開發一個系統,有個需求就是,忘記密碼後經過郵箱找回。如今的系統在註冊的時候都會強制輸入郵箱,其一目的就是 經過郵件綁定找回,能夠進行密碼找回。經過java發送郵件的功能我就不說了,重點講找回密碼。mysql

 

二、參考別人的思路發送郵件→請求郵件裏的URL→驗證url→{驗證成功修改密碼,不成功跳轉到失敗頁面}linux

重點就是如何生成這個url和如何解析這個url. 
須要注意的是一個url只能修改一次密碼,當同一賬號發送多封郵件,只有最後一封郵件的url 郵箱
git

 

三、加密能防止僞造攻擊,一次url只能驗證一次,而且綁定了用戶。生成url:   能夠用UUID生成隨機密鑰。 web

數字簽名 = MD5(用戶名+'$'+過時時間+‘$’+密鑰key) 
數據庫字段(用戶名(主鍵),密鑰key,過時時間) 
url參數(用戶名,數字簽名) ,密鑰key的生成:在每個用戶找回密碼時候爲這個用戶生成一個密鑰key ,
spring

 

url example:http://www.wechat68.com:80/CardSSHOK/checkLink?sid=K3xHOi4o/UihH5QYWBDfYA==&userName=123sql

 

 

 

 

生成過時時間,生成數字簽名,生成url,發送郵件.   AddU(用戶名,密鑰key,過時時間) 數據庫

 

使用到的數據庫以下 

session

 

package com.soq.card.web.action;

import java.sql.Timestamp;
import java.util.List;
import java.util.UUID;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.soq.card.biz.UserHander;
import com.soq.card.entity.Users;
import com.soq.card.tools.DBhepler;
import com.soq.card.tools.Mail;
import com.soq.card.tools.Md5;
import com.soq.card.web.base.BaseAction;

/**
 * @author javen
 * @Email zyw205@gmail.com
 * 
 */
public class PassEmailAction extends BaseAction {
    private Users users;
    private UserHander userHander;

    private String email;
    private String sid;
    private String userName;
    
    public String sendmail() {
        try {
            HibernateTemplate ht = this.getUserHander().getUsersDAO().getHibernateTemplate();
            SessionFactory factory = ht.getSessionFactory();
            Session session = factory.openSession();
            Criteria criteria = session.createCriteria(Users.class);
            criteria.add(Restrictions.eq("loginName", email));
            List<Users> list = criteria.list();
            if (list.size() > 0) {
                users=list.get(0);
                Mail mail = new Mail();

                String secretKey = UUID.randomUUID().toString(); // 密鑰
                Timestamp outDate = new Timestamp(System.currentTimeMillis() + 30 * 60 * 1000);// 30分鐘後過時
                long date = outDate.getTime() / 1000 * 1000;// 忽略毫秒數  mySql 取出時間是忽略毫秒數的
                
                DBhepler bhepler=new DBhepler();
                String sql="update users set outDate=?,validataCode=? where loginName=?;";
                String str[] ={outDate+"",secretKey,users.getLoginName()};
                bhepler.AddU(sql, str);
                
                //this.getUserHander().getUsersDAO().getHibernateTemplate().update(users); // 保存到數據庫
                System.out.println("   UserName>>>> "+users.getUserName());
                String key =users.getUserName() + "$" + date + "$" + secretKey;
                System.out.println(" key>>>"+key);
                String digitalSignature = Md5.md5(key);// 數字簽名

                String path = this.getRequest().getContextPath();
                String basePath = this.getRequest().getScheme() + "://"
                        + this.getRequest().getServerName() + ":"
                        + this.getRequest().getServerPort() + path + "/";
                String resetPassHref = basePath + "checkLink?sid="
                        + digitalSignature +"&userName="+users.getUserName();
                String emailContent = "請勿回覆本郵件.點擊下面的連接,重設密碼<br/><a href="
                        + resetPassHref + " target='_BLANK'>" + resetPassHref
                        + "</a>  或者    <a href=" + resetPassHref
                        + " target='_BLANK'>點擊我從新設置密碼</a>"
                        + "<br/>tips:本郵件超過30分鐘,連接將會失效,須要從新申請'找回密碼'" + key
                        + "\t" + digitalSignature;

                mail.setTo(email);
                mail.setFrom("XX");// 你的郵箱
                mail.setHost("smtp.163.com");
                mail.setUsername("XXX@163.com");// 用戶
                mail.setPassword("CXXX");// 密碼
                mail.setSubject("[二維碼名片]找回您的帳戶密碼");
                mail.setContent(emailContent);
                if (mail.sendMail()) {
                    System.out.println(" 發送成功");
                    this.getRequest().setAttribute("mesg", "重置密碼郵件已經發送,請登錄郵箱進行重置!");
                    return "sendMail";
                }
            } else {
                this.getRequest().setAttribute("mesg", "用戶名不存在,你不會忘記郵箱了吧?");
                return "noUser";
            }
        } catch (Exception e) {
            // TODO: handle exception 
            e.printStackTrace();
        }
        return null;
    }

    public String checkResetLink() {
        System.out.println("sid>>>" + sid);

        if (sid.equals("")  || userName.equals("")) {
            this.getRequest().setAttribute("mesg", "連接不完整,請從新生成");
            System.out.println(">>>>> null");
            return "error";
        }
        HibernateTemplate ht = this.getUserHander().getUsersDAO().getHibernateTemplate();
        SessionFactory factory = ht.getSessionFactory();
        Session session = factory.openSession();
        Criteria criteria = session.createCriteria(Users.class);
        criteria.add(Restrictions.eq("userName", userName));
        List<Users> list = criteria.list();
        if (list.size()>0) {
            users=list.get(0);
            
            Timestamp outDate = (Timestamp) users.getOutDate();
            System.out.println("outDate>>>"+outDate);
             if(outDate.getTime() <= System.currentTimeMillis()){ //表示已通過期
                 this.getRequest().setAttribute("mesg", "連接已通過期,請從新申請找回密碼.");
                 System.out.println("時間 超時");
                 return "error";
             }
             
             String key = users.getUserName()+"$"+outDate.getTime()/1000*1000+"$"+users.getValidataCode();//數字簽名
            
             System.out.println("key link》》"+key);
             String digitalSignature = Md5.md5(key);// 數字簽名
             
             System.out.println("digitalSignature>>>>"+digitalSignature);
              if(!digitalSignature.equals(sid)) {
                  this.getRequest().setAttribute("mesg", "連接不正確,是否已通過期了?從新申請吧.");
                      System.out.println("標示不正確");
                    return "error";
              }else {
                //連接驗證經過 轉到修改密碼頁面
                this.getRequest().setAttribute("user", users);
                return "success";
            }
        }else {
            this.getRequest().setAttribute("mesg", "連接錯誤,沒法找到匹配用戶,請從新申請找回密碼.");
            System.out.println("用戶不存在");
            return "error";
        }
    }

    public Users getUsers() {
        return users;
    }

    public void setUsers(Users users) {
        this.users = users;
    }

    public UserHander getUserHander() {
        return userHander;
    }

    public void setUserHander(UserHander userHander) {
        this.userHander = userHander;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

}

補充1:Timestamp類型對象在保存到數據的時候 毫秒精度會丟失。好比:2014-05-20 10:30:10.234  存到mysql數據庫的時候 變成 2013-05-20 10:30:10.0。時間變得不相同了,sid 匹配的時候不會相等。 因此我作了忽略精度的操做。dom

補充2:解決linux下面title中文亂碼

 

      sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
      mailMessage.setSubject(MimeUtility.encodeText(mailInfo.getSubject(), "UTF-8", "B"));      //解決linux郵件title亂碼


補充3:怎麼不直接把sid插入到users表呢。驗證的時候直接比較sid就ok了。

 

源碼下載地址  連接:http://pan.baidu.com/s/1sj1LBf3 密碼:fa4x

相關文章
相關標籤/搜索