基于SpringBoot实现邮箱找回密码


基于邮箱发送验证码的方式

》》源码下载地址:https://pan.quark.cn/s/c9917760d886

1. 实现思路

  1. 用户点击忘记密码
  2. 用户输入用户名以及邮箱,点击获取验证码
  3. 后端校验用户名以及邮箱,正确后生成验证码
  4. 生成的验证码作为value,前缀加用户名为key,放入redis中并设置过期时间
  5. 用户输入验证码以及新的密码点击保存
  6. 后端通过前缀+用户名获取验证码,校验验证码的正确性
  7. 密码修改成功

2. 前端UI页面

图为ProcessOn所画,可作为借鉴。也可设计为先验证用户名然后再进入改密码页面。

3. 发件邮箱要求

作者使用的是163邮箱(其他邮箱也基本一致),需要设置POP3/SMTP/IMAP

开启

  • IMAP/SMTP服务
  • POP3/SMTP服务
    开启会让设置授权码,授权码要记牢!后面需要写在配置里

再往下翻有163 SMTP服务器地址 等下需要配置在application.yml中

各家邮箱大同小异,企业邮箱的话应该是可以直接用的,不用开启。

4. 代码实现

4.1 依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

4.2 application.yml配置

# 配置邮箱服务器,账号密码等
spring:
  mail:
    host: smtp.163.com
    username: xxxxxx@163.com
    password: ERBDGXLVJAQMWMDI(授权码)

4.3 获取验证码controller

import com.clisoft.srmsbackend.common.response.ServerResponse;
import com.clisoft.srmsbackend.service.IMailService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 邮箱业务 前端控制器
 * @author zzw
 * @date 2022-01-14
 */
@Api(tags = "邮箱业务管理")
@RestController
@RequestMapping("/mail")
public class MailController {

    @Autowired
    private IMailService mailService;

    /**
     * 获取重置密码的验证码
     */
    @ApiOperation(value = "获取重置密码的验证码", notes = "获取重置密码的验证码", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "staffNumber", value = "用户编号(账号)", required = true, paramType = "form"),
            @ApiImplicitParam(name = "mailAddress", value = "邮箱地址", required = true, paramType = "form"),
    })
    @GetMapping("/getCode")
    public ServerResponse getCode(String staffNumber,String mailAddress){
        return mailService.getCode(staffNumber,mailAddress);
    }
}

4.4 ServiceImpl层

import com.clisoft.srmsbackend.common.constant.Constants;
import com.clisoft.srmsbackend.common.response.ServerResponse;
import com.clisoft.srmsbackend.config.MailCodeConfig;
import com.clisoft.srmsbackend.dao.entity.PersStaff;
import com.clisoft.srmsbackend.dao.mapper.PersStaffMapper;
import com.clisoft.srmsbackend.framework.redis.RedisCache;
import com.clisoft.srmsbackend.service.IMailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 邮箱业务 实现类
 *
 * @author zzw
 * @date 2022-01-14
 */
@Service
public class MailServiceImpl implements IMailService {

    @Autowired
    private PersStaffMapper persStaffMapper;

    @Autowired
    private MailCodeConfig mailCodeConfig;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String mailUserName;

    /**
     * 获取重置密码的验证码
     *
     * @param staffNumber 用户账号
     * @param mailAddress 用户邮箱
     * @return
     */
    @Override
    public ServerResponse getCode(String staffNumber, String mailAddress) {
        // 非空校验
        if (null == staffNumber || "".equals(staffNumber)) return ServerResponse.createByErrorMessage("账号不能为空!");
        if (null == mailAddress || "".equals(mailAddress)) return ServerResponse.createByErrorMessage("邮箱不能为空!");

        // 账号存在校验
        PersStaff persStaff = persStaffMapper.selectPersStaffByStaffNumber(staffNumber);
        if (null == persStaff) return ServerResponse.createBySuccessMessage("账号不存在!");
        if (!persStaff.getEmail().equals(mailAddress)) return ServerResponse.createByErrorMessage("输入邮箱和预留邮箱不一致!");

        String verifyCode = redisCache.getCacheObject(Constants.MAIL_CODE_KEY + staffNumber);
        if (verifyCode == null) {
            verifyCode = String.valueOf(new Random().nextInt(899999) + 100000);//生成短信验证码
        }
        Integer overtime = mailCodeConfig.getOvertime(); // 过期时间
        // 验证码存入redis并设置过期时间
        redisCache.setCacheObject(Constants.MAIL_CODE_KEY + staffNumber, verifyCode, overtime, TimeUnit.MINUTES);

        // 编写邮箱内容
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("<html><head><title></title></head><body>");
        stringBuilder.append("您好<br/>");
        stringBuilder.append("您的验证码是:").append(verifyCode).append("<br/>");
        stringBuilder.append("您可以复制此验证码并返回至科研管理系统找回密码页面,以验证您的邮箱。<br/>");
        stringBuilder.append("此验证码只能使用一次,在");
        stringBuilder.append(overtime.toString());
        stringBuilder.append("分钟内有效。验证成功则自动失效。<br/>");
        stringBuilder.append("如果您没有进行上述操作,请忽略此邮件。");
        MimeMessage mimeMessage = mailSender.createMimeMessage();

        // 发件配置并发送邮件
        try {
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
            //这里只是设置username 并没有设置host和password,因为host和password在springboot启动创建JavaMailSender实例的时候已经读取了
            mimeMessageHelper.setFrom(mailUserName);
            // 用户的邮箱地址
            mimeMessageHelper.setTo(mailAddress);
            // 邮件的标题
            mimeMessage.setSubject("邮箱验证-科研管理系统");
            // 上面所拼接的邮件内容
            mimeMessageHelper.setText(stringBuilder.toString(), true);
            mailSender.send(mimeMessage);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
        return ServerResponse.createBySuccessMessage("获取验证码成功,请查看移步您的邮箱" + mailAddress + "查看验证码!");
    }
}

4.5 修改密码controller

/**
     * 验证码重置密码
     */
    @ApiOperation(value = "验证码重置密码", notes = "验证码重置密码", httpMethod = "POST")
    @PostMapping("/codeUpdatePwd")
    public ServerResponse codeUpdatePwd(@RequestBody CodeUpdatePwdVo codeUpdatePwdVo){
        return persStaffService.codeUpdatePwd(codeUpdatePwdVo);
    }

4.6 修改密码ServiceImpl

 /**
     * 验证码重置密码
     *
     * @param codeUpdatePwdVo
     * @return
     */
    @Override
    public ServerResponse codeUpdatePwd(CodeUpdatePwdVo codeUpdatePwdVo) {
        String staffNumber = codeUpdatePwdVo.getStaffNumber();
        String code = codeUpdatePwdVo.getCode();
        String loginPassword = codeUpdatePwdVo.getLoginPassword();
        // 非空校验
        if (null == staffNumber || "".equals(staffNumber)) return ServerResponse.createByErrorMessage("账号不能为空!");
        if (null == code || "".equals(code)) return ServerResponse.createByErrorMessage("验证码不能为空!");
        if (null == loginPassword || "".equals(loginPassword)) return ServerResponse.createByErrorMessage("密码不能为空!");

        // 账号存在校验
        PersStaff persStaff = persStaffMapper.selectPersStaffByStaffNumber(staffNumber);
        if (null == persStaff) return ServerResponse.createBySuccessMessage("账号不存在!");

        // 验证码过期校验
        String cacheCode = redisCache.getCacheObject(Constants.MAIL_CODE_KEY + staffNumber); // 获取缓存中该账号的验证码
        if (cacheCode == null) {
            return ServerResponse.createByErrorMessage("验证码已过期,请重新获取!");
        }

        // 验证码正确性校验
        if (!cacheCode.equals(code)) {
            return ServerResponse.createByErrorMessage("验证码错误!");
        }

        // 修改密码
        int result = 0;
        try {
            result = persStaffMapper.updatePwdByStaffNumber(staffNumber, PasswordStorageUtil.createHash(codeUpdatePwdVo.getLoginPassword()));
        } catch (PasswordStorageUtil.CannotPerformOperationException e) {
            return ServerResponse.createByErrorMessage("密码加密时发生错误");
        }
        if (result > 0) {
            // 将验证码过期
            redisCache.expire(Constants.MAIL_CODE_KEY + staffNumber, 0);
            return ServerResponse.createBySuccessMessage("密码充值成功!请牢记您的密码!");
        }

        return ServerResponse.createByErrorMessage("未知错误,密码修改失败,请重试!");
    }

4.7 效果图

4.8 问题

  • 作者没有遇到什么问题,如有问题可留言讨论。

源码下载地址:https://pan.quark.cn/s/c9917760d886

  • 6
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七维大脑

打赏10元我只能获取8元...

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值