邮箱验证码登录的简易实现| 青训营笔记

980 阅读1分钟

这是我参与「第四届青训营 」笔记创作活动的的第十五天

写在前面

在写大项目时,在用户登录模块,我们选择邮箱验证码登录,所以特此记录邮箱验证码登录的后端代码实现


引入依赖

<!-- 1.邮箱依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
    <version>2.7.2</version>
</dependency>
<!-- 2.模板引擎 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- 3.validation -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- 4.HuTool -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.5</version>
</dependency>
<!-- Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 说明
    • 2.模板引擎是用于美化发送的邮件样式
    • 本邮件验证登录以qq邮箱作为发送箱,因此需要引入qq邮箱官网的依赖支持3.validation

配置

spring:
  mail:
    host: smtp.qq.com 
    username: # 用来发送邮件的邮箱账号
    password: # 授权码
    default-encoding: UTF-8
  redis:
    database: 1
    host: 127.0.0.1
    port: 6379
    password: # 密码
  • 说明
    • 需要登录自己的邮箱账号,在设置-账户-POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务那开启POP3/SMTP服务,同时获取授权码
    • 引入redis数据库是为了保存用户的验证码

使用实例

  • util,用于生成验证码
public class VerificationCodeUtil {
    /**
     * 随机生成验证码
     * @param length 长度为4位或者6位
     * @return
     */
    public static Integer getVerificationCode(int length){
        Integer code =null;
        if(length == 4){
            code = new Random().nextInt(9999);//生成随机数,最大为9999
            if(code < 1000){
                code = code + 1000;//保证随机数为4位数字
            }
        }else if(length == 6){
            code = new Random().nextInt(999999);//生成随机数,最大为999999
            if(code < 100000){
                code = code + 100000;//保证随机数为6位数字
            }
        }else{
            throw new RuntimeException("只能生成4位或6位数字验证码");
        }
        return code;
    }

    /**
     * 随机生成指定长度字符串验证码
     * @param length 长度
     * @return
     */
    public static String generateValidateCode4String(int length){
        Random rdm = new Random();
        String hash1 = Integer.toHexString(rdm.nextInt());
        String capstr = hash1.substring(0, length);
        return capstr;
    }
}
  • controller层
@PostMapping("/sendMsg")
public ResultVo<String> sendMsg(@RequestBody User user, HttpSession session){
    String email = user.getPhone();
    if (email == null) {
        throw new GlobalException(new CodeMsg("邮箱为空"));
    }
    log.info(email);

    // 获取发送邮箱验证码的HTML模板
    TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template",
            TemplateConfig.ResourceMode.CLASSPATH));
    Template template = engine.getTemplate("email-code.ftl");

    //获取验证码
    Integer code = VerificationCodeUtil.getVerificationCode(6);

    //发送验证码
    userService.send(new EmailRo(email, "邮箱验证码登录", template.render(Dict.create().set("code", code)), code));

    return ResultVo.success("验证码发送成功");
}
  • service层
//获取配置文件的信息
@Value("${spring.mail.host}")
private String host;
@Value("${spring.mail.username}")
private String username;
@Value("${spring.mail.password}")
private String password;

//sprintboot整合redis
@Resource
private RedisTemplate<String,Object> redisTemplate;

public void send(EmailRo emailRo) {
    //设置
    MailAccount account = new MailAccount();
    account.setHost(host);
    // 设置发送人信息
    account.setFrom("xxx" + "<" + username + ">");
    // 设置发送人名称
    account.setUser(username);
    // 设置发送授权码
    account.setPass(password);
    account.setAuth(true);
    // ssl方式发送
    account.setSslEnable(true);
    // 使用安全连接
    account.setStarttlsEnable(true);

    //发送邮件
    try {
        Mail.create(account)
                .setTos(emailRo.getEmail())
                .setTitle(emailRo.getSubject())
                .setContent(emailRo.getContent())
                .setHtml(true)
                //关闭session
                .setUseGlobalSession(false)
                .send();
        //将验证码保存到redis
        redisTemplate.opsForValue().set(emailRo.getEmail(), emailRo.getCode(),120, TimeUnit.SECONDS);
    } catch (Exception e){
        throw new GlobalException(new CodeMsg("邮件发送失败"));
    }
}
  • 模板文件email-code.ftl
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <style>
        @page {
            margin: 0;
        }
    </style>
</head>
<body>
<div class="header">
    <div style="padding: 10px;padding-bottom: 0px;">
        <p style="margin-bottom: 10px;padding-bottom: 0px;">尊敬的用户,您好:</p>
        <p style="text-indent: 2em; margin-bottom: 10px;">您正在申请邮箱验证,您的验证码为:</p>
        <p class="code-text">${code}</p>
        <div class="footer">
        </div>
    </div>
</div>
</body>
</html>

<style lang="css">
    body {
        margin: 0px;
        padding: 0px;
        font: 100% SimSun, Microsoft YaHei, Times New Roman, Verdana, Arial, Helvetica, sans-serif;
        color: #000;
    }

    .header {
        height: auto;
        width: 820px;
        min-width: 820px;
        margin: 0 auto;
        margin-top: 20px;
        border: 1px solid #eee;
    }

    .code-text {
        text-align: center;
        font-family: Times New Roman;
        font-size: 22px;
        color: #C60024;
        padding: 20px 0px;
        margin-bottom: 10px;
        font-weight: bold;
        background: #ebebeb;
    }

    .footer {
        margin: 0 auto;
        z-index: 111;
        width: 800px;
        margin-top: 30px;
        border-top: 1px solid #DA251D;
    }
</style>

写在最后

以上便是我的一些学习笔记,若有不足,欢迎指出