找回密码是系统登录中比较常见的操作。当用户忘记密码的时候,输入注册的邮箱后,系统会自动发送一个链接地址至注册邮箱,用户去邮箱点击链接地址后重新设置密码。新密码填写完成后提交,密码修改完成。此时用户就可以用新的密码重新登录系统了。
点击页面的找回密码链接以后在界面填写注册邮箱地址,然后点击提交;
后台对提交的邮箱地址进行验证,如果邮箱还未注册则提示邮箱地址无效,如果邮箱存在则发送链接到邮箱;
链接地址是一个URL,此URL的设计是一个重点,要具有唯一性和实效性,防止别人伪造URL地址来窃取修改密码;
用户点击邮箱里的URL地址,跳转到重置密码页面,用户重新填写密码后提交,则密码修改成功。
下面首先我们先来看URL生成的代码:
//向邮箱发送找回密码链接public void sendPwdEmail(){ //邮件类,自己对此类进行封装 Mail mail = new Mail(); String email = getPara("email"); //验证该邮箱是否存在 User user = User.dao.getUserByEmail(email); if(user!=null){ //设置此链接的有效期为30分钟 Timestamp outDate = new Timestamp(System.currentTimeMillis() + 30 * 60 * 1000);// 30分钟后过期 long date = outDate.getTime() / 1000 * 1000;// 忽略毫秒数 mySql 取出时间是忽略毫秒数的 //随机生成15位的字母数字字符串 String secretKey = CommonUtil.getRandomString(15); //数字加一串随机字符,生成唯一识别码 String digitalSignature = date + "$" + secretKey; //更新用户表,更新唯一码和链接到期时间字段 User.dao.updateUsersOutdate(email, outDate, digitalSignature); String path = this.getRequest().getContextPath(); String basePath = this.getRequest().getScheme() + "://" + this.getRequest().getServerName() + ":" + this.getRequest().getServerPort() + path + "/"; //找回密码链接URL地址 String resetPassHref = basePath + "login/resetPwd?sid=" + digitalSignature +"&userName="+ user.getStr("username"); String emailContent = "请勿回复本邮件.点击下面的链接,重设密码 " + resetPassHref + " " + " tips:本邮件超过30分钟链接将会失效,需要重新申请找回密码."; mail.setTo(email); mail.setSubject("邮箱找回您的账号密码!"); mail.setContent(emailContent); mail.send(); json.put("error", 0); json.put("msg", "邮件发送成功!请到邮箱查收密码链接!"); }else{ json.put("error", 1); json.put("msg", "该邮箱尚未注册!"); }}
当用户去邮箱点击链接地址时,此时需要解析URL地址是否有效,方法如下
//验证链接地址的有效性,重设密码public void resetPwd(){ //从URL获取sid和username参数 String sid = getPara("sid"); String uname =getPara("userName"); if(sid==null || "".equals(sid) || uname==null || "".equals(uname)){ render("redirect.html"); }else{ User user = User.dao.getUserByName(uname); String code = user.getStr("validataCode"); Timestamp ts = user.getTimestamp("outdate"); //URL地址只在半小时内有效,超过时间则无效,需重新申请 if(user !=null && code!=null && code.equals(sid) &&ts.getTime()>= System.currentTimeMillis()){ setAttr("email",user.get("email")); render("resetpwd.html"); } else { render("redirect.html"); } } }
发送的链接地址形式大致为:
链接若有效,则在页面重新填写新的密码然后提交,则密码更新成功。
附邮件类Mail类的封装:
public class Mail { //邮件标题 private String subject; //邮件正文 private String content; //邮件发送地址 private InternetAddress from; //邮件接收地址 private InternetAddress to; public Mail() { try { this.from = new InternetAddress(DictKeys.EMAIL_USERNAME); this.to = new InternetAddress(DictKeys.EMAIL_USERNAME); } catch (Exception e) { e.printStackTrace(); } this.subject = "From Jfinal"; } public void setTo(String to) { try { this.to = new InternetAddress(to); } catch (Exception e) { e.printStackTrace(); } } public void setFrom(String from) { try { this.from = new InternetAddress(from); } catch (Exception e) { e.printStackTrace(); } } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public InternetAddress getFrom() { return from; } public InternetAddress getTo() { return to; } //发送邮件方法 public void send(){ new Thread(new Runnable() { @Override public void run() { //设置属性 Properties props = new Properties(); props.setProperty("mail.transport.protocol", DictKeys.EMAIL_PROTOCOL); props.setProperty("mail.smtp.host", DictKeys.EMAIL_HOST); props.setProperty("mail.smtp.auth", "true"); //邮件授权,需要邮件用户名、密码 Authenticator auth = new EmailAuth(DictKeys.EMAIL_USERNAME,DictKeys.EMAIL_PASSWORD); Session session = Session.getDefaultInstance(props, auth); MimeMessage message = new MimeMessage(session); try { message.setSubject(getSubject()); message.setFrom(getFrom()); message.setRecipient(RecipientType.TO, getTo()); message.setSentDate(new Date()); message.setContent(content, "text/html;charset=UTF-8"); Transport.send(message); } catch (MessagingException e) { e.printStackTrace(); } } }).start(); }}