Java实现邮箱找回密码实例代码
通过邮件找回密码功能的实现
1、最近开发一个系统,有个需求就是,忘记密码后通过邮箱找回。现在的系统在注册的时候都会强制输入邮箱,其一目的就是 通过邮件绑定找回,可以进行密码找回。通过java发送邮件的功能我就不说了,重点讲找回密码。
2、参考别人的思路:发送邮件→请求邮件里的url→验证url→{验证成功修改密码,不成功跳转到失败页面}
重点就是如何生成这个url和如何解析这个url.
需要注意的是一个url只能修改一次密码,当同一帐号发送多封邮件,只有最后一封邮件的url 邮箱
3、加密能防止伪造攻击,一次url只能验证一次,并且绑定了用户。生成url: 可以用uuid生成随机密钥。
数字签名 = md5(用户名+'′+过期时间+‘′+过期时间+‘'+密钥key)
数据库字段(用户名(主键),密钥key,过期时间)
url参数(用户名,数字签名) ,密钥key的生成:在每一个用户找回密码时候为这个用户生成一个密钥key ,
生成过期时间,生成数字签名,生成url,发送邮件. addu(用户名,密钥key,过期时间)
使用到的数据库如下 :
找回邮箱密码代码如下:
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 匹配的时候不会相等。 所以我做了忽略精度的操作。
补充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/1cl8hkq
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。