Jsp邮件找回密码全攻略
@ author Joy-zhuang
一般大型网站我们登录的时候,密码忘了都有个功能可以找回密码。
细数下大致的方法:
1.直接把密码发送到你的邮箱去。一般是临时密码。2.短信验证,成本较高。3.密保问题4.发送一个链接到你邮箱点击即可更改密码。
个人认为第四种方法最经济实惠,这次也主要都是在搞这个。
搞了一个晚上,单单邮件发送功能写了快300行,虽然很多是注释和空格,被舍友一说,用python只写了20几行,不禁膜拜PYTHON了!不过不管怎样写出来了,封装好了,下次要用就方便了。代码大部分是参考网上的和一些自己写的。
首先说下思路:
用户填写自己的邮箱时,需要查看该邮箱是否与用户ID绑定的邮箱想匹配,只有当匹配的时候才会发送邮件。这封邮件中最重要的是一个链接地址:url = baseUrl + “?uid=” + uid + “&validkey=” + validkey;这个地址含有两个参数,id用户的id,validkey验证code,这是一个通过MD5加密过的字符串。效验MD5就是用来确保文件在传输过程中未被修改用的,这个加密过的字符串应该包含用户的id+过期时间+随机数validkey=md5(uid + “|” + outdate + “|” + secretKey);
说白了,就是你要找回密码,你就得先输入你的帐号和邮箱。然后系统去判断,帐号和邮箱是匹配的。那么就在这一瞬间再在另外一张表写下信息(usrId,outdate,url)即你的ID,过期的时间(用现在的时间加上X分钟的有效期),URL即发送的链接。
发送的链接 = baseUrl + “?uid=” + uid + “&validkey=” + validkey;
比如说我在本地的地址是localhost:8080/homeSeller/resetPassword.jsp这个是我重置密码的页面地址。那我再在地址栏加上’?’ 再在后面填写传入的属性与对应的值即可传值。比如我的一次链接:localhost:8080/homeSeller/resetPassword.jsp?uid=zhuang123&validkey=36B0F10812DE6D2B0D3B2DC044F9A27D意思就是传入id,以及vaildkeyvaildkey在之前我们已经写入数据库了!
填写成功后,利用JAVAMAIL发送邮件到指定邮箱。然后你点击那个链接,并且传值。这个时候就在JSP中判断一下对应userId的validkey是不是和数据库中的一样,以及currentTime是不是比outdate大即是否过期。如果都满足的话就跳转到更改密码的页面。更改密码就是简单的SQL,这里就不讲了。
ok,下面讲下代码:
首先是
(1)数据库层(DAO):上面说的把信息插入数据库的代码(代码都是挺简单的增删改查
//找回密码,插入信息 ,这里的date是java.sql.Date public int insertInfor(Connection con,String userId,String email,Timestamp date,String signature) throws SQLException { String sql = "insert into findPass(userId,email,outdate,signature) values(?,?,?,?)"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, userId); pstmt.setString(2, email); pstmt.setTimestamp(3,date); pstmt.setString(4, signature); int res = pstmt.executeUpdate(); pstmt.close(); con.close(); return res; } //找回密码,查询是否可以修改密码 public boolean isChangePass(String userId,String validkey) throws Exception { DbUtil dbUtil = new DbUtil(); Connection con = dbUtil.getCon(); String sql = "select * from findPass where userId = ?"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, userId); ResultSet res = pstmt.executeQuery(); if(res.last()) { String signature = res.getString("signature"); if(!validkey.equals(signature)){ pstmt.close(); con.close(); return false; } else{ long current = System.currentTimeMillis(); long time = res.getTimestamp("outdate").getTime(); if(current> time){ pstmt.close(); con.close(); return false; } else{ pstmt.close(); con.close(); return true; } } } else{ pstmt.close(); con.close(); return false; } }
(2)Servlet代码 就是根据思路对应的处理
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //分割处理 String method = request.getParameter("method"); if(method.equals("find")){ String userId = request.getParameter("userId"); String userEmail = request.getParameter("userEmail"); Connection con = null; try { con = dbUtil.getCon(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } boolean flag = false; try { flag = userDao.judgeUserEamil(userId, userEmail); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if(flag){ long currentTime = System.currentTimeMillis() + 120000; Date time = new Date(currentTime); Timestamp ts = new Timestamp(time.getTime()); Random random = new Random(); String key = userId + "|" + ts + "|" + random.nextInt(); String signature = MD5Util.MD5(key); try { int res = userDao.insertInfor(con, userId, userEmail, ts, signature); if(res==1) { SendMail sendmail = new SendMail(); String url = "localhost:8080/homeSeller/resetPassword.jsp"+"?uid=" + userId + "&validkey=" + signature; sendmail.send(userEmail, url); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (AddressException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (MessagingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { request.setAttribute("error", "用户名和邮箱不匹配,请重新输入!"); } } //重置密码 else if (method.equals("reset")){ String userId = request.getParameter("userid"); String password = request.getParameter("password1"); try { Connection con = dbUtil.getCon(); userDao.updatePassword(con, userId,password); request.setAttribute("error", "修改成功,请重新登录!"); request.getRequestDispatcher("login.jsp").forward(request, response); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
(3)工具类
工具类一共有两类MD5加密,实现上面说的validkey的加密处理防止人工识别出来。
package com.homeSeller.util; import java.security.MessageDigest; import java.security.MessageDigest; public class MD5Util { public final static String MD5(String s) { char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; try { byte[] btInput = s.getBytes(); // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest mdInst = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 mdInst.update(btInput); // 获得密文 byte[] md = mdInst.digest(); // 把密文转换成十六进制的字符串形式 int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } public static void main(String[] args) { System.out.println(MD5Util.MD5("20121221")); System.out.println(MD5Util.MD5("加密")); } }
第二类是邮件发送类
JAVA MAIL是利用现有的邮件账户发送邮件的工具,比如说,我在网易注册一个邮箱账户,通过JAVA Mail的操控,我可以不亲自登录网易邮箱,让程序自动的使用网易邮箱发送邮件。这一机制被广泛的用在注册激活和垃圾邮件的发送等方面。JavaMail可以到http://www.oracle.com/technetwork/java/javamail/index-138643.html进行下载,并将mail.jar添加到classpath即可。
JAVA邮件发送的大致过程是这样的的:
1、构建一个继承自javax.mail.Authenticator的具体类,并重写里面的getPasswordAuthentication()方法。此类是用作登录校验的,以确保你对该邮箱有发送邮件的权利。
2、构建一个properties文件,该文件中存放SMTP服务器地址等参数。
3、通过构建的properties文件和javax.mail.Authenticator具体类来创建一个javax.mail.Session。Session的创建,就相当于登录邮箱一样。剩下的自然就是新建邮件。
4、构建邮件内容,一般是javax.mail.internet.MimeMessage对象,并指定发送人,收信人,主题,内容等等。
5、使用javax.mail.Transport工具类发送邮件。
这里我参考写出来的邮件类是只支持SMTP 而不支持另外两种的,所以也没发时间去写工厂类了。不过SMTP应该就够了吧。今天TX有BUG发送不出去换了个邮箱就OK了。
1、首先是继承自javax.mail.Authenticator的一个具体类。getPasswordAuthentication()方法也就是构建一个PasswordAuthentication对象并返回,有点费解JAVA Mail这样的设计意图,可能是javax.mail.Authenticator为我们提供了附加的保证安全的验证措施吧。
package com.homeSeller.util; import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; public class MailAuthenticator extends Authenticator{ private String username; private String password; public MailAuthenticator(String username,String password) { this.username = username; this.password = password; } String getPassword(){ return password; } @Override protected PasswordAuthentication getPasswordAuthentication(){ return new PasswordAuthentication(username,password); } String getUsername(){ return username; } public void setPassword(String password){ this.password = password; } public void setUsername(String username){ this.username = username; } }
2、邮件发送类,剩下的步骤都是在这个类实现的。代码中的SimpleMail是封装了邮件主题和内容的一个POJO。觉得在一个方法参数中既包含主题又包含内容,不太合适,故重载了此方法。还有就是因为大多数邮箱的SMTP服务器地址都是可以通过邮箱地址算出来,简单起见,提供了一个不需要SMTP服务器地址的构造器。
package com.homeSeller.util; import java.util.List; import java.util.Properties; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage.RecipientType; public class SimpleMailSender { /* * 简单邮件发送器,可单发,群发 */ /** * * 发送邮件的props文件 */ private final transient Properties props = System.getProperties(); /* * 邮件服务器登录验证 */ private transient MailAuthenticator authenticator; /** * 邮箱session */ private transient Session session; /** * 初始化邮件发送器 * * @param smtpHostName * SMTP邮件服务器地址 * @param username * 发送邮件的用户名(地址) * @param password * 发送邮件的密码 */ public SimpleMailSender(final String smtpHostName,final String username,final String password) { init(username,password,smtpHostName); } /** * 初始化邮件发送器 * * @param username * 发送邮件的用户名(地址),并以此解析SMTP服务器地址 * @param password * 发送邮件的密码 * */ public SimpleMailSender(final String username,final String password){ //通过邮箱地址解析出smtp服务器,对大多数邮箱都管用 final String smtpHostName = "smtp."+username.split("@")[1]; init(username,password,smtpHostName); } /** * 初始化 * * @param username * 发送邮件的用户名(地址) * @param password * 密码 * @param smtpHostName * SMTP主机地址 */ private void init(String username,String password,String smtpHostName) { //初始化 props props.put("mail.smtp.auth","true"); props.put("mail.smtp.host",smtpHostName); //验证 authenticator = new MailAuthenticator(username,password); //创建session session = Session.getInstance(props,authenticator); } /** * 发送邮件 * * @param recipient * 收件人邮箱地址 * @param subject * 邮件主题 * @param content * 邮件内容 * * @throws AddressException * @throws MessagingException */ public void send(String recipient,String subject,Object content) throws AddressException,MessagingException{ //创建mime类型邮件 final MimeMessage message = new MimeMessage(session); //设置发信人 message.setFrom(new InternetAddress(authenticator.getUsername())); //设置收件人 message.setRecipient(RecipientType.TO,new InternetAddress(recipient)); //设置主题 message.setSubject(subject); //设置邮件内容 message.setContent(content.toString(),"text/html;charset=utf-8"); //发送 Transport.send(message); } /** * * 群发邮件 * * @param recipients * 收件人们 * @param subject * 主题 * @param content * 内容 * throws AddressException * throws MessagingException */ public void send(List<String> recipients,String subject ,Object content) throws AddressException ,MessagingException{ //创建Mime类型邮件 final MimeMessage message = new MimeMessage(session); //设置发信人 message.setFrom(new InternetAddress(authenticator.getUsername())); //设置收信人们 final int num = recipients.size(); InternetAddress[] addresses = new InternetAddress[num]; for(int i=0;i<num;i++) { addresses[i] = new InternetAddress(recipients.get(i)); } message.setRecipients(RecipientType.TO,addresses); //设置主题 message.setSubject(subject); //设置邮件内容 message.setContent(content.toString(),"text/html;charset=utf-8"); //发送 Transport.send(message); } /** * 发送邮件 * * @param recipient * 收件人邮箱地址 * @param mail * 邮件对象 * @throws AddressException * @throws MessagingException */ public void send(String recipient,SimpleMail mail) throws AddressException,MessagingException{ send(recipient,mail.getSubject(),mail.getContent()); } /** * 群发邮件 * * @param recipients * 收件人们 * @param * 邮件对象 * @throws AddressException * @throws MessagingException * */ public void send(List<String> recipients,SimpleMail mail) throws AddressException,MessagingException { send(recipients,mail.getSubject(),mail.getContent()); } } 3.POJO:SimpleMail package com.homeSeller.util; /* * SimpleMail * PROJ */ public class SimpleMail { private String Content; private String Subject; public String getContent() { return Content; } public void setContent(String Content) { this.Content = Content; } public String getSubject() { return Subject; } public void setSubject(String Subject) { this.Subject = Subject; } }
4.最终的用来发送的类
package com.homeSeller.util; import java.util.List; import java.util.ArrayList; import javax.mail.MessagingException; import javax.mail.internet.AddressException; public class SendMail { public void send(String email,String url) throws AddressException, MessagingException { SimpleMailSender sms = new SimpleMailSender("[email protected]”,”password"); String recipients = email; sms.send(recipients, "HomeSeller找回密码","尊敬的HomeSeller用户,为了找回您的密码,请在两分钟之内点击以下连接:"+url+" 如果不是您本人操作,请忽略此消息。"); } public static void main(String[] args) throws AddressException, MessagingException{ SimpleMailSender sms = new SimpleMailSender("[email protected]","383160100033"); ArrayList<String> recipients = new ArrayList<String>(); recipients.add("[email protected]"); for(String recipient:recipients){ sms.send(recipients, "test测试","hello hrwhisper."); } } }
——————————————————————————————————————
到这里基本OK 所有东西串接起来,就很好的实现了密码找回了。
以前不懂原理,看到邮件发送来的都不知道是什么东西,现在懂了自然高兴,学习应该建立在这种不断学习不断满足的过程!
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。