springBoot+redis实现通过邮箱验证码发送验证码

业务需求:用户输入账号和邮箱,向后台发送获取验证码的请求,通过验证码,用户可以重置自己的密码
步骤:

  1. 验证用户:用户输入账户和邮箱,后台验证用户是否存在
  2. 处理验证码:通过用户验证,生成验证码,将邮箱和验证码作为k-v存储到redis中,并将验证码发送都用户邮箱
  3. 判断验证码:用户输入验证码,后台检测验证码是否正确

效果展示:
判断账户和邮箱
发送验证码
验证码错误

邮箱收到验证码
重置密码
在这里插入图片描述
代码展示:
后台部分

/**验证用户信息并发送验证码**
//service
/**
     * 通过用户名和邮箱查询用户
     * @param userName 用户名
     * @param Email 邮箱
     * @return 用户对象信息
     */
    public SysUser selectUserByUserNameAndEmail(String userName, String Email);
     /**
     * 通过用户有名和邮箱查询用户
     * @param userName 用户名
     * @param email 邮箱
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserByUserNameAndEmail(String userName, String email) {
        return userMapper.selectUserByUserNameAndEmail(userName,email);
    }

//mapper
 /**
     * 通过用户有名和邮箱查询用户
     * @param userName 用户名
     * @param email 邮箱
     * @return 用户对象信息
     */
    public SysUser selectUserByUserNameAndEmail(@Param("userName") String userName, @Param("email") String email);    
    
    <--mapper.xml-->
     <select id="selectUserByUserNameAndEmail" resultMap="SysUserResult">
		select * from sys_user where u.user_name = #{userName} and u.email = #{email} 
	</select>

//controller
 /**
     * 验证邮箱并发送验证码
     */
    @GetMapping("/verifyUserAndSendCode/{userName}/{email}")
    public AjaxResult verifyUserAndSendCode(@PathVariable("userName") String userName,
                                     @PathVariable("email") String email) throws Exception {
        SysUser user = userService.selectUserByUserNameAndEmail(userName, email);
        //验证账户是否存在
        if (user == null){
            return AjaxResult.error("账户或邮箱错误!");
        } else if(user.getStatus().equals("1")){
            return AjaxResult.error("该用户已停用,无法重置密码!");
        }else{
            //key邮箱号,value验证码
            String code = redisTemplate.opsForValue().get(email);   //需要注入redisTemplate<String,String>
            //从redis中获取验证码,取到返回success
            if (!StringUtils.isEmpty(code)){
                return AjaxResult.success();
            }
            //获取不到,生成随机验证码
            code = GenPassWordUtil.getPassWordOne(6);
            //调用service方法,通过邮箱服务发送验证码
            String result = sendEmailService.sendAuthCode(email, code);
            //生成的验证码放在redis中,设置有效时间:5分钟
            if (result.equals("Success")){
                redisTemplate.opsForValue().set(email,code,5, TimeUnit.MINUTES);
                return AjaxResult.success("验证码发送成功");
            } else {
                return AjaxResult.error("邮件发送出错");
            }
        }
    }
/**判断验证码并重置密码**
//service
 /**
         * 验证用户输入的验证码是否正确
         * @param toEmail 发送的用户邮箱
         * @param code 验证码
         * @return
         */
        public boolean checkAuthCode(String toEmail,String code){
                String redisCode = redisTemplate.opsForValue().get(toEmail);
                return redisCode != null && redisCode.equals(code);
        }
        
        /**
     * 重置用户密码
     * 
     * @param user 用户信息
     * @return 结果
     */
    public int resetPwd(SysUser user);
      /**
     * 重置用户密码
     * 
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int resetPwd(SysUser user)
    {
        return userMapper.updateUser(user);
    }
//mapper
 /**
     * 修改用户信息
     * 
     * @param user 用户信息
     * @return 结果
     */
    public int updateUser(SysUser user);    
<!--mapper.xml-->
	<update id="updateUser" parameterType="SysUser">
 		update sys_user
 		<set>
 		<if test="password != null and password != ''">password = #{password},</if>
 		</set>
 		where user_id = #{userId}
	</update>
//controller
 /**
     * 判断验证码并重置密码
     */
    @GetMapping("/checkAuthCode/{userName}/{email}/{authCode}")
    public AjaxResult checkAuthCode(@PathVariable("userName") String userName,
                                    @PathVariable("email") String email,
                                    @PathVariable("authCode") String authCode) throws Exception {
        boolean checkAuthCode = sendEmailService.checkAuthCode(email, authCode);
        if (checkAuthCode){
            SysUser user = userService.selectUserByUserNameAndEmail(userName,email);
            String newPassword = GenPassWordUtil.getPassWordOne(8);
            user.setPassword(newPassword);
            int i = userService.resetPwd(user);
            System.out.println(i);
            sendEmailService.sendEmail(user.getEmail(), user.getNickName(), newPassword);
            return AjaxResult.success("密码已重置");
        } else {
            return AjaxResult.error("验证码错误");
        }
    }    
        

使用的工具类

//生成密码工具类
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class GenPassWordUtil {
    /**
     * 生成随机密码生成方式一
     * 密码字典 -> 随机获取字符
     *
     * @param len 生成密码长度(最短为4位)
     * @return 随机密码
     */
    public static String getPassWordOne(int len) {
        // 如果len 小于等于3
        if (len <= 3) {
            throw new RuntimeException("密码的位数不能小于3位!");
        }
        //生成的随机数
        int i;
        //生成的密码的长度
        int count = 0;
        // 密码字典
        char[] str = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
        // 大写字母密码字典
        List<Character> bigStrList = Arrays.asList('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z');
        Set<Character> bigStrSet = new HashSet<>(bigStrList);
        // 小写字母的密码字典
        List<Character> upperStrList = Arrays.asList('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
        Set<Character> upperStrSet = new HashSet<>(upperStrList);
        // 数字的密码字典
        List<Character> numStrList = Arrays.asList('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
        Set<Character> numStrSet = new HashSet<>(numStrList);

        StringBuilder builder = new StringBuilder();
        Random r = new Random();
        boolean isContainBigChar = false;
        boolean isContainUpperChar = false;
        boolean isContainNumChar = false;
        while (count < len - 3) {
            //生成 0 ~ 密码字典-1之间的随机数
            i = r.nextInt(str.length);
            builder.append(str[i]);
            count++;
            if (!isContainBigChar && bigStrSet.contains(str[i])) {
                isContainBigChar = true;
            }
            if (!isContainUpperChar && upperStrSet.contains(str[i])) {
                isContainUpperChar = true;
            }
            if (!isContainNumChar && numStrSet.contains(str[i])) {
                isContainNumChar = true;
            }
        }
        // 如果不存在的,则加,确保一定会存在数字,大写字母,小写字母
        if (!isContainBigChar) {
            builder.append(bigStrList.get(r.nextInt(bigStrList.size())));
        }
        if (!isContainUpperChar) {
            builder.append(upperStrList.get(r.nextInt(upperStrList.size())));
        }
        if (!isContainNumChar) {
            builder.append(numStrList.get(r.nextInt(numStrList.size())));
        }
        while (builder.length() < len) {
            builder.append(str[r.nextInt(str.length)]);
        }
        return builder.toString();
    }
}

//邮箱发送工具
public String sendAuthCode(String toEmail,String code) throws Exception{
                String subject = "邮箱验证码";        //主题
                String body = "<!DOCTYPE html>"     //内容
                        +"<html>"
                        +"<head>"
                        +"<meta charset=\"utf-8\">"
                        +"<title>验证码</title>"
                        +"</head>"
                        +"<body>"
                        +"	<p>您好:</p>"
                        +"  	<p>&nbsp;&nbsp;&nbsp;&nbsp;您的验证码:<strong style=\"color:red;\"><i>"+code+"</i></strong></p>"
                        +"	<p>&nbsp;&nbsp;&nbsp;&nbsp;有效时间为5分钟,请尽快使用并不告诉他人</p>"
                        +"  	<p>支持</p>"
                        +"</body>"
                        +"</html>";
                EmailUtils emailUtils = EmailUtils.entity(smtpHost, emailName, password, toEmail, null, subject, body, null);
                emailUtils.send();
                return "Success";
        }
       	
       	import com.sinosoft.common.config.EmailAuthenticator;

import javax.activation.CommandMap;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.activation.MailcapCommandMap;
import javax.mail.*;
import javax.mail.internet.*;
import java.util.List;
import java.util.Properties;

/**
 * 使用javax.mail发送邮件
 *
 * @author: gblfy
 * @date 2021-06-22
 *
 * <p>
 * 参数列表:
 * 1.邮件服务器
 * 2.发件人邮箱
 * 3.发件人的授权密码
 * 4.邮件主题
 * 5.收件人,多个收件人以半角逗号分隔
 * 6.抄送,多个抄送以半角逗号分隔
 * 7.正文,可以用html格式的哟
 * </p>
 */
public class EmailUtils {

    private String smtpHost; // 邮件服务器地址
    private String sendUserName; // 发件人的用户名
    private String sendUserPass; // 发件人密码

    private MimeMessage mimeMsg; // 邮件对象
    private Multipart mp;// 附件添加的组件

    private void init() {
        // 创建一个密码验证器
        EmailAuthenticator authenticator = null;
        authenticator = new EmailAuthenticator(sendUserName, sendUserPass);

        // 实例化Properties对象
        Properties props = System.getProperties();
        props.put("mail.smtp.host", smtpHost);
        props.put("mail.smtp.auth", "true"); // 需要身份验证
        props.put("mail.smtp.starttls.enable", "false");

        // 建立会话
        Session session = Session.getDefaultInstance(props, authenticator);
        // 置true可以在控制台(console)上看到发送邮件的过程
        session.setDebug(true);
        // 用session对象来创建并初始化邮件对象
        mimeMsg = new MimeMessage(session);
        // 生成附件组件的实例
        mp = new MimeMultipart();
    }

    private EmailUtils(String smtpHost, String sendUserName, String sendUserPass, String to, String cc, String mailSubject,
                       String mailBody, List<String> attachments) {
        this.smtpHost = smtpHost;
        this.sendUserName = sendUserName;
        this.sendUserPass = sendUserPass;

        init();
        setFrom(sendUserName);
        setTo(to);
        setCC(cc);
        setBody(mailBody);
        setSubject(mailSubject);
        if (attachments != null) {
            for (String attachment : attachments) {
                addFileAffix(attachment);
            }
        }

    }

    /**
     * 邮件实体
     *
     * @param smtpHost     邮件服务器地址
     * @param sendUserName 发件邮件地址
     * @param sendUserPass 发件邮箱密码
     * @param to           收件人,多个邮箱地址以半角逗号分隔
     * @param cc           抄送,多个邮箱地址以半角逗号分隔
     * @param mailSubject  邮件主题
     * @param mailBody     邮件正文
     * @param attachments  附件路径
     * @return
     */
    public static EmailUtils entity(String smtpHost, String sendUserName, String sendUserPass, String to, String cc,
                                    String mailSubject, String mailBody, List<String> attachments) {
        return new EmailUtils(smtpHost, sendUserName, sendUserPass, to, cc, mailSubject, mailBody, attachments);
    }

    /**
     * 设置邮件主题
     *
     * @param mailSubject
     * @return
     */
    private boolean setSubject(String mailSubject) {
        try {
            mimeMsg.setSubject(mailSubject);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 设置邮件内容,并设置其为文本格式或HTML文件格式,编码方式为UTF-8
     *
     * @param mailBody
     * @return
     */
    private boolean setBody(String mailBody) {
        try {
            BodyPart bp = new MimeBodyPart();
            bp.setContent("<meta http-equiv=Content-Type content=text/html; charset=UTF-8>" + mailBody,
                    "text/html;charset=UTF-8");
            // 在组件上添加邮件文本
            mp.addBodyPart(bp);
        } catch (Exception e) {
            System.err.println("设置邮件正文时发生错误!" + e);
            return false;
        }
        return true;
    }

    /**
     * 添加一个附件
     *
     * @param filename 邮件附件的地址,只能是本机地址而不能是网络地址,否则抛出异常
     * @return
     */
    public boolean addFileAffix(String filename) {
        try {
            if (filename != null && filename.length() > 0) {
                BodyPart bp = new MimeBodyPart();
                FileDataSource fileds = new FileDataSource(filename);
                bp.setDataHandler(new DataHandler(fileds));
                bp.setFileName(MimeUtility.encodeText(fileds.getName(), "utf-8", null)); // 解决附件名称乱码
                mp.addBodyPart(bp);// 添加附件
            }
        } catch (Exception e) {
            System.err.println("增加邮件附件:" + filename + "发生错误!" + e);
            return false;
        }
        return true;
    }

    /**
     * 设置发件人地址
     *
     * @param from 发件人地址
     * @return
     */
    private boolean setFrom(String from) {
        try {
            mimeMsg.setFrom(new InternetAddress(from));
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 设置收件人地址
     *
     * @param to 收件人的地址
     * @return
     */
    private boolean setTo(String to) {
        if (to == null)
            return false;
        try {
            mimeMsg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 设置抄送
     *
     * @param cc
     * @return
     */
    private boolean setCC(String cc) {
        if (cc == null) {
            return false;
        }
        try {
            mimeMsg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc));
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * no object DCH for MIME type multipart/mixed报错解决
     */
    private void solveError() {
        MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
        mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
        mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
        mc.addMailcap(
                "multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed; x-java-fallback-entry=true");
        mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
        CommandMap.setDefaultCommandMap(mc);
        Thread.currentThread().setContextClassLoader(EmailUtils.class.getClassLoader());
    }

    /**
     * 发送邮件
     *
     * @return
     */
    public boolean send() throws Exception {
        mimeMsg.setContent(mp);
        mimeMsg.saveChanges();
        System.out.println("正在发送邮件....");
        solveError();
        Transport.send(mimeMsg);
        System.out.println("发送邮件成功!");
        return true;
    }
}

前端部分

//js
// 验证账户信息和发送验证码
export function verifyUserAndSendCode(username,email) {
  return request({
    url: '/system/user/verifyUserAndSendCode/' + username +"/" + email,
    method: 'get'
  })
}
// 验证用户输入验证码
export function checkAuthCode(username,email,code) {
  return request({
    url: '/system/user/checkAuthCode/' + username + "/" + email + "/" + code,
    method: 'get'
  })
}

//vue
  /** 获取验证码 */
    sendCode: function(){
      this.$refs["resetPassForm"].validate((valid) =>{
        if (valid){
          var userName = this.resetPassForm.username;
          var email = this.resetPassForm.email; 
          console.log(userName);
          console.log(email);
          verifyUserAndSendCode(userName,email).then((response) =>{
            this.msgSuccess("验证码发送成功")
          })
          if (this.canClick) return
          this.canClick = true
          this.btnText = this.totalTime + 's后重新发送'
          let clock = window.setInterval(()=> {
          this.totalTime--
          this.btnText = this.totalTime + 's后重新发送'
           if (this.totalTime < 0){
              window.clearInterval(clock)
              this.btnText = '重新发送验证码'
              this.totalTime = 300
              this.canClick = false
        }
      },1000)
    }
  })  
},
    /** 取消 */
    cancel(){
      this.resetPasswordDialog = false;
    },
    /** 重置密码表单重置 */
    reset(){
      this.resetPassForm ={
        username:undefined,
        email:undefined,
        code:undefined,
      };
      this.resetForm("resetPassForm");
    },
    /** 重置密码确认按钮 */
    submitForm: function(){
      var username = this.resetPassForm.username;
      var email = this.resetPassForm.email; 
      var code = this.resetPassForm.code;
      console.log(username);
      console.log(email);
      console.log(code);
      if (code == null) {
        this.msgError("请输入用户信息!");
        this.resetPasswordDialog = true;
      } else {
        checkAuthCode(username,email,code).then((response) => {
          this.resetPasswordDialog = false;
          this.msgSuccess("密码已重置,请邮箱查收!");
        })
      }
    },
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值