Java实现邮箱找回密码实例代码
作者:智慧云端日记 发布时间:2022-01-12 11:48:57
通过邮件找回密码功能的实现
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


猜你喜欢
- 各位小伙伴们大家早上好,不知道你的《第三行代码》已经读到哪里了?有些朋友的阅读速度真是令人印象深刻,我记得在《第三行代码》刚刚发售一周不到的
- Maven的安装安装Maven之前要确保已经安装好了jdk,并且配置好了环境变量JAVA_HOME。具体安装步骤如下:1. 从ap
- String类原生的字符串处理方法short s=1;s=s+1;与short s=1;s+=1;的区别一、“+&
- /// 构造随机数 种子static int GetRandomSeed(){ byte[] byt
- 1.基本思路我现阶段的分页查询的实现是基于sql语句的。select * from user where id limit a, b构造出相
- RestTemplate 请求接收自定义400+ 或500+错误场景当服务端自定义400错误返回体时,使用restTemplate 请求接收
- 背景:最近需要做一个任务:C# PDF文件需要传输为JPG图片。一开始没有头绪,最后去github找到了现在我用的PdfiumViewer组
- 一. 假设需求场景在我们开发的过程中,经常出现两个对象存在一对多或多对一的关系。如何在程序在表明这两个对象的关系,以及如何利用这种关系优雅地
- 引入假定我们有两个项目:Cup 和 Water,其中 Cup 表示主项目,而 Water 表示子模块项目。其中 Cup 的远程仓库地址为 g
- 什么是JSON?JSON (JavaScript Object Notation) is a lightweight data-interc
- 摘要本文主要讲解mall整合SpringTask的过程,以批量修改超时订单为例。SpringTask是Spring自主研发的轻量级定时任务工
- 因为案例比较简单,所以简单用AndroidApplication -> Game -> Stage 搭建框架 一、主入口,无特殊
- 很多童鞋反应在吧项目导入到eclipse(myeclipse)时中文会有乱码,修改了编码格式后还是乱码,这里给大家介绍一下关于中文乱码时修改
- 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的。什么
- 我们知道,Maven 是通过仓库对依赖进行管理的,当 Maven 项目需要某个依赖时,只要其 POM 中声明了依赖的坐标信息,Maven 就
- mybatis获取表中某一列的最大值这个问题这两天也是找了好久才找到解决办法,在此记录一下。获取表中数据某一列的最大值,在mapper.xm
- 0.写在前面2020-5-18更新这个东西已经是两年前的了,现在问我具体细节我也不是很清楚了,而且现在review两年前的代码感觉写的好烂。
- 本文实例讲述了在Linux上运行C#的方法。分享给大家供大家参考。具体方法如下:在任何一个平台(操作系统+硬件体系)上,编写和运行程序的三个
- 在使用多线程的时候有时候我们会使用 java.util.concurrent.Executors的线程池,当多个线程异步执行的时候,我们往往
- 门面模式又叫外观模式(Facade Pattern),主要用于隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。我们知道电视剧