通过邮件找回密码功能的实现
1、最近开发一个系统,有个需求就是,忘记密码后通过邮箱找回。现在的系统在注册的时候都会强制输入邮箱,其一目的就是 通过邮件绑定找回,可以进行密码找回。通过java发送邮件的功能我就不说了,重点讲找回密码。
2、参考别人的思路:发送邮件→请求邮件里的URL→验证url→{验证成功修改密码,不成功跳转到失败页面}
重点就是如何生成这个url和如何解析这个url.
需要注意的是一个url只能修改一次密码,当同一帐号发送多封邮件,只有最后一封邮件的url 邮箱
3、加密能防止伪造攻击,一次url只能验证一次,并且绑定了用户。生成url: 可以用UUID生成随机密钥。
数字签名 = MD5(用户名+'′+过期时间+‘′+过期时间+‘'+密钥key)
数据库字段(用户名(主键),密钥key,过期时间)
url参数(用户名,数字签名) ,密钥key的生成:在每一个用户找回密码时候为这个用户生成一个密钥key ,
生成过期时间,生成数字签名,生成url,发送邮件. AddU(用户名,密钥key,过期时间)
使用到的数据库如下 :
找回邮箱密码代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
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中文乱码
1
2
|
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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。