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 条评论
登录 后参与评论

相关文章

来自专栏安恒网络空间安全讲武堂

CTF逆向--安卓篇

题目(来源:Jarvis-OJ): Androideasy DD Android Easy DD - Android Normal FindPass Smali...

6286
来自专栏一个番茄说

函数响应式编程框架RxSwift 学习——Subject

简单的比喻下,Observable像是一个水管,会源源不断的有水冒出来。Subject就像一个水龙头,它可以套在水管上,接受Observable上面的事件。但是...

772
来自专栏好好学java的技术栈

微信小程序Java登录流程(ssm实现具体功能和加解密隐私信息问题解决方案)

signature,//签名、encryptedData,//用户敏感信息、iv//解密算法的向量:

4447
来自专栏Kubernetes

从源码看kubernetes与CNI Plugin的集成

libcni cni项目提供了golang写的一个library,定义了集成cni插件的应用需调用的cni plugin接口,它就是libcni。其对应的In...

3267
来自专栏青蛙要fly的专栏

Android技能树 — Rxjava取消订阅小结(2):RxLifeCycle

现在很多项目都在使用Rxjava了,对于RxJava的使用,估计都很熟悉了,但是很多人在使用RxJava的时候容易产生内存泄漏问题,比如我们在用RxJava配合...

2303
来自专栏三流程序员的挣扎

RxJava 线程调度和源码阅读

通过 Scheduler 来控制被观察者在哪个线程发射,观察者在哪个线程接收。默认情况,发射时在哪个线程,接收就在哪个线程。

913
来自专栏Android开发实战

RxJava for Android学习笔记

Android工程引入RxJava-android 请引入Rxandroid库: compile 'io.reactivex:rxandroid:1.2.1' ...

943
来自专栏Jack的Android之旅

RxJava的消息发送和线程切换

RxJava相信大家都非常了解吧,今天分享一下RxJava的消息发送和线程源码的分析。最后并分享一个相关demo,让大家更加熟悉我们天天都在用的框架。

1062
来自专栏芋道源码1024

熔断器 Hystrix 源码解析 —— 命令执行(一)之正常执行逻辑

本文主要基于 Hystrix 1.5.X 版本 1. 概述 2. #applyHystrixSemantics(...) 3. TryableSemaphor...

5068
来自专栏Seebug漏洞平台

漏洞分析】Shiro RememberMe 1.2.4 反序列化导致的命令执行漏洞

概述 Apache Shiro 在 Java 的权限及安全验证框架中占用重要的一席之地,在它编号为550的 issue 中爆出严重的 Java 反序列化漏洞。下...

1.2K5

扫码关注云+社区