今天给大家介绍一下很常用的一个功能,就是邮件找回密码功能。找回密码一般会有:1.邮件找回密码、2短信找回密码、3问题找会密码。

关于邮件找回密码的原理思想为:

1.用户申请找回密码功能,服务器将会发送一个url地址到用户注册的邮箱中去。

2.用户打开邮箱点击url地址跳转到相应的网页中修改密码。

3.修改完密码就可以重新登录了。

这些过程中最重要的就是url地址安全的问题了,如何才能保证url地址不会被篡改就是核心问题了。

下面是我对于这个问题的一些解决方案,如有不足或有问题请和及时我联系QQ:208017534

步骤:

1.搭建邮件服务器(这里我使用的是James服务器,如果这方面有什么不懂的可以看我以前写的博客内容)。

2.生成url地址:

这里生成url地址有三大要素:用户账号(account)+过期时间(outtime)+随机值(key),然后通过md5将这些要素进行散列加密生成sid值。然后将outtime,sid,account存入数据库中进行邮件url地址是否有效的验证。

数据库截图:

SpringBoot中实现邮件找回密码的功能_springboot

关键代码:
生成随机值的工具类:

package example.utils;
public class RandomUtils {
    //获取m~n范围内的整数
    public static int getRandom(int m,int n){
        int random=(int)(Math.random()*(n-m))+m;
        return random;
    }

    //获取位数为n的随机数
    public static int getRandom(int length){
        int m=getNumber(length);
        int n=m*10-1;
        int random=(int)(Math.random()*(n-m))+m;
        return random;
    }

    public static int getNumber(int n){
        if(n<1){
            n=1;
        }
        if(n==1){
            return 1;
        }else{
            n=n-1;
            return 10*getNumber(n);
        }
    }
}
Md5检验的工具类:

package example.encrypt;
import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Encrypt {
    /**利用MD5进行加密
     * @param str  待加密的字符串
     * @return  加密后的字符串
     */
    public static String EncoderByMd5(String str){
        //确定计算方法
        MessageDigest md5= null;
        String result="";
        try {
            md5 = MessageDigest.getInstance("MD5");
            result=new BASE64Encoder().encode(md5.digest(str.getBytes("utf-8")));
        } catch (Exception e) {
            e.printStackTrace();
        }
        //加密后的字符串
        return result;
    }
}
生成url核心代码:

业务层代码:

  //找回密码
    public Object findPassowrd(String basePath,String account){
        Manage manage= manageDao.findByAccount(account);
        String code,info,result;
        if(manage==null){
            code="001";
            info="Account does not exist";
            result="";
        }else{
            //生成邮件url唯一地址
            String key= RandomUtils.getRandom(6)+"";
            Timestamp outDate = new Timestamp(System.currentTimeMillis()+(long)(30*60*1000));//30分钟后过期             //忽略毫秒数
            long outtimes=outDate.getSysUpTime();
            String sid=account+"&"+key+"&"+outtimes;
            MailRetrieve mailRetrieve=new MailRetrieve(account,Md5Encrypt.EncoderByMd5(sid),outtimes);
            MailRetrieve findMailRetrieve=mailRetrieveDao.findByAccount(account);
            if(findMailRetrieve!=null){
                mailRetrieveDao.delete(findMailRetrieve);
            }
            mailRetrieveDao.save(mailRetrieve);
            result =  basePath+"user/reset_password?sid="+Md5Encrypt.EncoderByMd5(sid)+"&userName="+account;
            code="005";
            info="Email retrieve password";
        }
        return JsonUtils.toJson(code,info,result);
    }
控制层的代码:

    @RequestMapping("/back")
    @ResponseBody
    public Object backManage(HttpServletRequest request,String account){
        String path = request.getContextPath();
        String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
        return manageService.findPassowrd(basePath,account);
    }
邮件实体类代码:

package example.entity;
import javax.persistence.*;
@Entity
@Table(name = "myweb_mail_retrieve")
public class MailRetrieve{
    private static final long serialVersionUID = -1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "account", nullable = true, length = 20)
    private String account;

    @Column(name = "sid", nullable = true, length = 25)
    private String sid;

    @Column(name = "out_time", nullable = true, length = 20)
    private long outTime;

    public MailRetrieve() {
    }

    public MailRetrieve(String account, String sid, long outTime) {
        this.account = account;
        this.sid = sid;
        this.outTime = outTime;
    }

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }


    public MailRetrieve(String account) {
        this.account = account;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public long getOutTime() {
        return outTime;
    }

    public void setOutTime(long outTime) {
        this.outTime = outTime;
    }
}
3.通过James邮件服务器将url地址发送到用户邮箱中(具体过程看以前的案例介绍)。

4.点击url地址,服务器进行邮件url地址检验,检验完跳转到相应的界面中进行处理:

业务层代码:

 //邮件U找回密码URL校验
    public Object verifyMail(String sid,String account){
        String code,info;
        boolean result=false;
        MailRetrieve mailRetrieve=mailRetrieveDao.findByAccount(account);
        long outTime=mailRetrieve.getOutTime();
        Timestamp outDate = new Timestamp(System.currentTimeMillis());
        long nowTime=outDate.getSysUpTime();
        System.out.println("nowTime:"+nowTime);
        if(outTime<=nowTime){
            code="006";
            info="verifyMail time is overdue";
        }else if("".equals(sid)){
            code="007";
            info="sid is incomplete content";
        }else if(!sid.equals(mailRetrieve.getSid())){
            code="008";
            info="sid is error";
        }else{
            code="000";
            info="no error";
            result=true;
        }
        return JsonUtils.toJson(code,info,result);
    }
控制层代码:

    @RequestMapping("/verify")
    @ResponseBody
    public Object verifyMail(String sid,String account){
        return manageService.verifyMail(sid,account);
    }
这整个过程中需要注意的有:1时间是否过期要判断好、2保存邮件url信息的时候要注意数据库中是否有这个信息存在,如果存在则删除重新添加。

如果大家对文章有什么问题或者疑意之类的,可以加我订阅号在上面留言,订阅号上面我会定期更新最新博客。如果嫌麻烦可以直接加我wechat:lzqcode
SpringBoot中实现邮件找回密码的功能_springboot_02