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

今天给大家介绍一下很常用的一个功能,就是邮件找回密码功能。找回密码一般会有: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地址是否有效的验证。

数据库截图:

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

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信息的时候要注意数据库中是否有这个信息存在,如果存在则删除重新添加。

上面介绍的只是部分的核心代码,如果大家想要全部的源代码或者对本文内容有啥异议的都可以联系我QQ:208017534     欢迎打扰!!!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小灰灰

spring-boot & ffmpeg 搭建一个音频转码服务

利用FFMPEG实现一个音频转码服务 提供一个音频转码服务,主要是利用ffmpeg实现转码,利用java web对外提供http服务接口 背景 音频转码服务...

8426
来自专栏菩提树下的杨过

ActiveMQ笔记(5):JMX监控

系统上线运行后,及时监控报警是很必要的手段,对于ActiveMQ而言,主要监控的指标有:MQ本身的健康状况、每个队列的生产者数量、消费者数量、队列的当前消息数等...

2018
来自专栏Java 源码分析

SpringBoot 笔记(十一):Servlet容器

1912
来自专栏工作积累

Android获取QQ和微信的聊天记录,并保存到数据库

(该方法只适用于监控自己拥有的微信或者QQ ,无法监控或者盗取其他人的聊天记录。本文只写了如何获取聊天记录,服务器落地程序并不复杂,不做赘述。写的仓促,有错别字...

3.5K12
来自专栏Hadoop实操

如何通过Livy的RESTful API接口向Kerberos环境的CDH集群提交作业

在前面的文章Fayson介绍了《Livy,基于Apache Spark的开源REST服务,加入Cloudera Labs》、《如何编译Livy并在非Kerber...

82311
来自专栏haifeiWu与他朋友们的专栏

使用Spring Boot实现博客统计服务

作为一个后端开发,在微服务,server mesh等概念满天飞的时代,持续学习能力是不能丢的,因此楼主最近也研究好多RPC,NETTY,Spring Boot等...

2453
来自专栏Android机动车

使用Retrofit+RxJava实现带进度下载文件

Retrofit+RxJava已经是目前市场上最主流的网络框架,使用它进行平常的网络请求异常轻松,之前也用Retrofit做过上传文件和下载文件,但发现:使用R...

951
来自专栏Java帮帮-微信公众号-技术文章全总结

Web-第二十一天 Web商城实战一【悟空教程】

public class BaseServlet extends HttpServlet {

1274
来自专栏史上最简单的Spring Cloud教程

SpringBoot非官方教程 | 第二十五篇:2小时学会springboot

一.什么是spring boot Takes an opinionated view of building production-ready Spring ...

2036
来自专栏xingoo, 一个梦想做发明家的程序员

大数据之Oozie——源码分析(一)程序入口

工作中发现在oozie中使用sqoop与在shell中直接调度sqoop性能上有很大的差异。为了更深入的探索其中的缘由,开始了oozie的源码分析之路。今天第...

2507

扫码关注云+社区