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

相关文章

来自专栏程序员宝库

Webpack 详解

webpack是现代前端开发中最火的模块打包工具,只需要通过简单的配置,便可以完成模块的加载和打包。那它是怎么做到通过对一些插件的配置,便可以轻松实现对代码的构...

953
来自专栏Python

使用python的email、smtplib、poplib模块收发邮件

https://blog.csdn.net/weixin_35955795/article/details/52881044

340
来自专栏Android群英传

Clipboard还能玩出花

772
来自专栏智能大石头

5,ORM组件XCode(动手)

本篇才真正是XCode教程第一篇。《速览》是为了以最简洁的语言最短小的篇幅去吸引开发者;《简介》则是对XCode组件和XCode开发模式的一个整体介绍,让开发者...

1889
来自专栏一个会写诗的程序员的博客

第7章 Spring Boot集成模板引擎小结

因为Spring Boot其实是对Spring生态的封装整合打包,以简化开发中使用Spring框架。所以 Spring Boot在集成模板引擎过程中,其实就是对...

653
来自专栏Golang语言社区

从websocket看go的应用

Go是互联网时代的通用编程语言。这样它就和命令行时代的C语言、图示界面时代的C++、以及互联网早期的Java语言等有不同的侧重。它强调保持自身的精巧和独立,从而...

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

jetty 9 嵌入式开发示例

jetty 9 嵌入应用程序后,小型的web应用直接打成一个单独的jar包,就可以直接运行,非常适合做Demo演示或云端集群部署。 主要代码: JettySer...

18810
来自专栏PHP实战技术

PHP经典面试题目汇总(上篇)

1、双引号和单引号的区别 双引号解释变量,单引号不解释变量 双引号里插入单引号,其中单引号里如果有变量的话,变量解释 双引号的变量名后面必须要有一个非数字、字母...

2677
来自专栏张善友的专栏

ASP.NET MVC 4 - 测试驱动 ASP.NET MVC

测试驱动 ASP.NET MVC Keith Burnell 下载代码示例 模型-视图-控制器 (MVC) 模式的核心是将 UI 功能划分成三个组成部分。模型表...

1937
来自专栏Google Dart

Flutter 构建完整应用手册-持久化

如果我们有一小部分我们想要保存的键值,我们可以使用shared_preferences插件。

792

扫码关注云+社区