> 技术文档 > 【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录

  📝个人主页:哈__

期待您的关注 

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录

目录

一、前期准备

1 开启邮箱服务

2 SpringBoot导入依赖

3 创建application.yml配置文件 

4 创建数据库文件

 5 配置redis服务

二、验证邮件发送功能 

三、注册功能实现邮箱验证

1 创建User实体类

2 创建UserParam

3 创建CaptchaService

4 创建EmailTemplateEnum

5 创建CaptchaServiceImpl

 6 创建CaptchaController

7 创建LoginController 

四、创建登陆页面 

1 login.html 

2 register.html


 

在实际的开发当中,不少的场景中需要我们使用更加安全的认证方式,同时也为了防止一些用户恶意注册,我们可能会需要用户使用一些可以证明个人身份的注册方式,如短信验证、邮箱验证等。

一、前期准备

为了实现邮箱认证服务,我们需要提供出来一个邮箱作为验证码的发送者,这里我使用的是QQ邮箱。

1 开启邮箱服务

首先打开QQ邮箱,然后找到设置,点击账号。

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录

然后找到下方的邮件协议服务,打开。因为这里我已经打开了,而且服务开启也较为简单,需要我们发送一个短信到指定的号码,可能会收取一定的费用,不过不是很多,好像是几毛钱。

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录 开启之后会给你一个授权码,一定要记住这个授权码,发邮件的时候需要这个。

2 SpringBoot导入依赖

核心的就是mail依赖,因为我这个项目东西不少,为了方便我就全拷贝过来了,可能有的用不到。

  1.8 UTF-8 UTF-8 2.7.6 UTF-8 UTF-8 1.8 3.4.3.1 3.3.2 1.7    org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-mail   org.slf4j slf4j-log4j12   org.apache.commons commons-lang3   com.mysql mysql-connector-j   org.projectlombok lombok true   org.springframework.boot spring-boot-starter-test test   com.baomidou mybatis-plus-boot-starter ${mybatisplus.version}   com.baomidou mybatis-plus-generator ${mybatisplus.generator}   org.apache.velocity velocity ${mybatisplus.velocity}   org.springframework.boot spring-boot-devtools   org.springframework.boot spring-boot-starter-data-redis   com.alibaba fastjson 1.2.56  

3 创建application.yml配置文件 

spring: #邮件服务配置 mail: host: smtp.qq.com #邮件服务器地址 protocol: smtp #协议 username: #发送邮件的邮箱也就是你开通服务的邮箱 password: #开通服务后得到的授权码 default-encoding: utf-8 #邮件内容的编码 redis: host: 127.0.0.1 port: 6379 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mail username: root password: # 数据库的密码

4 创建数据库文件

在上边的配置文件中你也看到了,我们用到了mysql还有redis。

DROP TABLE IF EXISTS `user`;CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Compact;-- ------------------------------ Records of user-- ----------------------------INSERT INTO `user` VALUES (1, \'admin\', \'123456\');INSERT INTO `user` VALUES (2, \'123456\', \'123456\');SET FOREIGN_KEY_CHECKS = 1;

 5 配置redis服务

在之前的文章当中我有说到过安装redis的事情,大家可以看看我这篇文章。【Spring】SpringBoot整合Redis,用Redis实现限流(附Redis解压包)_springboot 限流 redis-CSDN博客

二、验证邮件发送功能 

大家可以先看一下我的项目结构。其中的一些代码是我学习另一位大佬的文章,这篇文章也是对该大佬文章的一个总结。蒾酒-CSDN博客

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录

我们最重要的邮件发送工具 就是util包下的EmailApi。将以下代码导入后,创建一个测试方法。

import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Value;import org.springframework.core.io.FileSystemResource;import org.springframework.mail.SimpleMailMessage;import org.springframework.mail.javamail.JavaMailSender;import org.springframework.mail.javamail.MimeMessageHelper;import org.springframework.stereotype.Component;import javax.annotation.Resource;import javax.mail.internet.MimeMessage;import java.io.File;import java.util.Objects;/** * @author mijiupro */@Component@Slf4jpublic class EmailApi { @Resource private JavaMailSender mailSender; @Value(\"${spring.mail.username}\") private String from ;// 发件人 /** * 发送纯文本的邮件 * @param to 收件人 * @param subject 主题 * @param content 内容 * @return 是否成功 */ @SneakyThrows(Exception.class) public boolean sendGeneralEmail(String subject, String content, String... to){ // 创建邮件消息 SimpleMailMessage message = new SimpleMailMessage(); message.setFrom(from); // 设置收件人 message.setTo(to); // 设置邮件主题 message.setSubject(subject); // 设置邮件内容 message.setText(content); // 发送邮件 mailSender.send(message); return true; } /** * 发送html的邮件 * @param to 收件人 * @param subject 主题 * @param content 内容 * @return 是否成功 */ @SneakyThrows(Exception.class) public boolean sendHtmlEmail(String subject, String content, String... to){ // 创建邮件消息 MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setFrom(from); // 设置收件人 helper.setTo(to); // 设置邮件主题 helper.setSubject(subject); // 设置邮件内容 helper.setText(content, true); // 发送邮件 mailSender.send(mimeMessage); log.info(\"发送邮件成功\"); return true; } /** * 发送带附件的邮件 * @param to 收件人 * @param subject 主题 * @param content 内容 * @param filePaths 附件路径 * @return 是否成功 */ @SneakyThrows(Exception.class) public boolean sendAttachmentsEmail(String subject, String content, String[] to, String[] filePaths) { // 创建邮件消息 MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setFrom(from); // 设置收件人 helper.setTo(to); // 设置邮件主题 helper.setSubject(subject); // 设置邮件内容 helper.setText(content,true); // 添加附件 if (filePaths != null) { for (String filePath : filePaths) { FileSystemResource file = new FileSystemResource(new File(filePath)); helper.addAttachment(Objects.requireNonNull(file.getFilename()), file); } } // 发送邮件 mailSender.send(mimeMessage); return true; } /** * 发送带静态资源的邮件 * @param to 收件人 * @param subject 主题 * @param content 内容 * @param rscPath 静态资源路径 * @param rscId 静态资源id * @return 是否成功 */ @SneakyThrows(Exception.class) public boolean sendInlineResourceEmail(String subject, String content, String to, String rscPath, String rscId) { // 创建邮件消息 MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); // 设置发件人 helper.setFrom(from); // 设置收件人 helper.setTo(to); // 设置邮件主题 helper.setSubject(subject); //html内容图片 String contentHtml = \"这是邮件的内容,包含一个图片:\"+content+\"\"; helper.setText(contentHtml, true); //指定讲资源地址 FileSystemResource res = new FileSystemResource(new File(rscPath)); helper.addInline(rscId, res); mailSender.send(mimeMessage); return true; }}

 进行邮件发送的测试。

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录

 看看结果,成功的发过来了。

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录

 接下来就要进行登录注册功能的开发了。

三、注册功能实现邮箱验证

1 创建User实体类

@Data@EqualsAndHashCode(callSuper = false)public class User implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = \"id\", type = IdType.AUTO) private Integer id; private String account; private String password;}

2 创建UserParam

@Data@EqualsAndHashCode(callSuper = false)public class UserParam implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = \"id\", type = IdType.AUTO) private Integer id; private String account; private String password; private String emailCode; private String email;}

3 创建CaptchaService

public interface CaptchaService { boolean sendCaptcha(String email);}

4 创建EmailTemplateEnum

这一步我没有选择创建CaptchaServiceImpl,因为这个类中涉及到了一些核心的代码,而我们一些类还没有创建完,我们先创建这样的一个枚举类,这个枚举类的作用就是定义我们发送邮件的一个模板,我们在发送邮件的时候,直接向模板内插入内容就可以了。

ublic enum EmailTemplateEnum { // 验证码邮件 VERIFICATION_CODE_EMAIL_HTML(\"用户你好,你的验证码是:

%s

请在五分钟内完成注册\",\"登录验证\"), // 用户被封禁邮件通知 USER_BANNED_EMAIL(\"用户你好,你已经被管理员封禁,封禁原因:%s\", \"封禁通知\"); private final String template; private final String subject; EmailTemplateEnum(String template, String subject) { this.template = template; this.subject = subject; } public String getTemplate(){ return this.template; } public String set(String captcha) { return String.format(this.template, captcha); } public String getSubject() { return this.subject; }}

5 创建CaptchaServiceImpl

首先把我们前端传过来的邮箱加一个前缀,用于redis中的存储,因为我们不仅可以有邮箱认证还可以有手机认证。

 @Resource StringRedisTemplate stringRedisTemplate; @Resource EmailApi emailApi; @Override public boolean sendCaptcha(String email) { sendMailCaptcha(\"login:email:captcha:\"+email); return true; }

 在redis当中,验证码的存储使用的是Hash结构,Hash存储了验证码,验证次数,还有上一次的发送时间,因为我们要限制一分钟发送的次数。一分钟内我们只能发一条短信,验证码在redis中的过期时间为五分钟,在验证码未过期之前发送的认证,都会让这个发送次数加一,倘若发送的次数达到了5次还要发送,那么就封禁一天不让发送短信。

例如,在3:30:30的时候发送了一次短信,一分钟后,3:31:30的时候又发送了短信,直到3:35:30的时候又发了一次,此时的发送次数已经达到了5,这时候就会封一天,因为每次发送验证码的时候,redis都存储着上一次还没过期的验证码,所以发送次数会增加。

下边讲一下代码。

先从redis中找到这个hash结构,如果hash结构的值不为空并且达到了发送次数上限,就封禁一天,否则的话看一下上一次的发送时间是否存在,如果存在的话,判断一下当前时间和上一次的发送时间间隔是否大于60秒,如果小于60秒那么不让发送。如果正常发送短信,那么就把发送的次数加1,然后用随机数生成一个六位数的验证码,发送验证码,并且向redis中保存刚才的hash结构。

 private boolean sendMailCaptcha(String key){ BoundHashOperations hashOps = stringRedisTemplate.boundHashOps(key); // 初始检查 String lastSendTimestamp = hashOps.get(\"lastSendTimestamp\"); String sendCount = hashOps.get(\"sendCount\"); if(StringUtils.isNotBlank(sendCount)&&Integer.parseInt(sendCount)>=5){ hashOps.expire(24, TimeUnit.HOURS); throw new RuntimeException(\"验证码发送过于频繁\"); } if(StringUtils.isNotBlank(lastSendTimestamp)){ long lastSendTime = Long.parseLong(lastSendTimestamp); long currentTime = System.currentTimeMillis(); long elapsedTime = currentTime - lastSendTime; if(elapsedTime < 60 * 1000){ throw new RuntimeException(\"验证码发送过于频繁\"); } } int newSendCount = StringUtils.isNotBlank(sendCount) ? Integer.parseInt(sendCount) + 1 : 1; String captcha = RandomStringUtils.randomNumeric(6); try { sendCaptcha(key,captcha); } catch (Exception e) { return false; } hashOps.put(\"captcha\", captcha); hashOps.put(\"lastSendTimestamp\", String.valueOf(System.currentTimeMillis())); hashOps.put(\"sendCount\", String.valueOf(newSendCount)); hashOps.expire(5, TimeUnit.MINUTES); // 设置过期时间为5分钟 return true; }

发送验证码调用的是下边的函数。

 private void sendCaptcha(String hashKey, String captcha) thorw Exception{ // 根据hashKey判断是发送邮件还是短信,然后调用相应的发送方法 if(\"email\".equals(hashKey.split(\":\")[1])){ if (!emailApi.sendHtmlEmail(EmailTemplateEnum.VERIFICATION_CODE_EMAIL_HTML.getSubject(),  EmailTemplateEnum.VERIFICATION_CODE_EMAIL_HTML.set(captcha),hashKey.split(\":\")[3])) { throw new RuntimeException(\"发送邮件失败\"); } } }

 6 创建CaptchaController

@RestController@RequestMapping(\"/captcha\")public class CaptchaController { @Resource CaptchaService captchaService; @Resource EmailApi emailApi; @RequestMapping(\"/getCaptcha\") public Result sendCaptcha(String email){ boolean res = captchaService.sendCaptcha(email); if(res){ return new Result(\"发送成功\",200,null); } return new Result(\"发送失败\",500,null); }}

7 创建LoginController 

UserSevice的东西都很简单,都是mybatisplus的内容,如果不太了解可以看我这篇文章【Spring】SpringBoot整合MybatisPlus的基本应用_简单的springboot+mybatisplus的应用程序-CSDN博客

我这里并没有用UserService封装认证的过程,直接写到controller中了,大家能看懂就好。仅供学习使用。 

@Controllerpublic class LoginController { @Autowired UserService userService; @Autowired StringRedisTemplate stringRedisTemplate; @GetMapping(\"/\") public String Login(){ return \"redirect:/pages/login.html\"; } @RequestMapping(\"/register\") @ResponseBody public Result registerUser( UserParam user ){ String email = user.getEmail(); String emailCode = user.getEmailCode(); BoundHashOperations hashOps = stringRedisTemplate.boundHashOps(\"login:email:captcha:\"+email); String code = hashOps.get(\"captcha\"); if(!Objects.equals(code, emailCode)){ return new Result(\"验证码错误\",400,null); } User user1 = userService.getOne(new LambdaQueryWrapper() .eq(User::getAccount,user.getAccount())); //如果有这个用户的信息要拒绝注册 if(user1!=null){ return new Result(\"\",100,null); } User saveUser = new User(); BeanUtils.copyProperties(user,saveUser); System.out.println(user); System.out.println(saveUser); boolean save = userService.save(saveUser); if(!save){ return new Result(\"注册失败\",300,null); } return new Result(\"注册成功\",200,null); }}

到此为止,验证码的注册功能就已经实现完成了。

我们现在要做一个前端页面。

四、创建登陆页面 

在resources目录下创建static文件夹。在pages目录下添加login.html和register.html。至于jquery呢就要大家自己去找了。

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录

 

1 login.html 

   Document   $(function() { $(\".btn\").on(\"click\", function () { var account = $(\".account\").val() var password = $(\".password\").val() console.log(account) console.log(password) $.ajax({  type: \"get\",  url: \"/login?&account=\" + account + \"&password=\" + password,  success: function (data) { if (data.code === 200) { window.location.href = \"../pages/index.html\" }else{ alert(\"登陆失败,请检查账号或者密码\") }  } }) }) });   *{ padding: 0; margin: 0px; text-decoration: none; } body { background-image: url(../images2/1.jpg); background-size:cover; background-attachment:fixed; } .loginbox { height: 280px; width: 26%; margin: 340px auto; background-color: rgb(158, 151, 158); opacity: 0.7; text-align: center; } .loginbox .top { display: block; height: 42px; background: linear-gradient(90deg,pink,red,pink,yellow,red); padding-top: 15px; font-size: 20px; font-weight: 600; color: black; } .loginbox span { color: black; font-weight: 500; font-size: 18px; } .loginbox input[type=text], .loginbox input[type=password] { height: 20px; border: none; border-radius: 4px; outline: none; } .loginbox input[type=button] { width: 40%; height: 24px; border: none; border-radius: 4px; margin: 0 auto; outline: none; } .loginbox .a { display: flex; margin: 20px auto; width: 45%; justify-content: space-between; } .loginbox .a a { color: white; } .loginbox .a a:hover { color: rgb(228, 221, 228); }  
邮箱简易发送系统
账号:

密码:

2 register.html

   Document    $(function(){ // 注册按钮点击事件 $(\".btn\").on(\"click\",function(){ var account = $(\".account\").val().trim(); var password = $(\".password\").val().trim(); var emailCode = $(\".emailCode\").val().trim(); var email = $(\".email\").val().trim(); $.ajax({  type:\"post\",  url:\"/register\",  data:{\"account\":account,\"password\":password,\"emailCode\":emailCode,\"email\":email},  success:function(data){ if(data.code=== 100){ alert(\"该账号已存在\"); }else if(data.code === 300){ alert(\"账号注册失败\"); }else if(data.code === 400){ alert(\"验证码错误\"); }else{ alert(\"账号注册成功\"); window.location.href=\"../pages/login.html\"; }  } }); }); // 发送验证码按钮点击事件 $(\".sendCode\").on(\"click\", function(){ var email = $(\".email\").val().trim(); if(email === \"\") {  alert(\"请输入邮箱\");  return; } // 发送验证码请求 $.ajax({  type:\"get\",  url:\"/captcha/getCaptcha?email=\"+email,  success:function(data){ console.log(data) if(data.code === 200){ alert(\"验证码已发送到邮箱\"); // 启动倒计时 startCountdown(60); } else { alert(\"验证码发送失败,请重试\"); }  } }); }); // 启动倒计时函数 function startCountdown(seconds) { var timer = seconds; $(\".sendCode\").prop(\"disabled\", true); var countdown = setInterval(function() {  $(\".sendCode\").val(timer + \"秒后可重新发送\");  timer--;  if (timer < 0) { clearInterval(countdown); $(\".sendCode\").prop(\"disabled\", false); $(\".sendCode\").val(\"发送验证码\");  } }, 1000); } });   *{ padding: 0; margin: 0px; text-decoration: none; } body { background-image: url(../images2/1.jpg); background-size: cover; background-attachment: fixed; } .loginbox { height: 380px; /* 调整高度以适应新字段 */ width: 26%; margin: 340px auto; background-color: rgb(158, 151, 158); opacity: 0.7; text-align: center; } .loginbox .top { display: block; height: 42px; background: linear-gradient(90deg, pink, red, pink, yellow, red); padding-top: 15px; font-size: 20px; font-weight: 600; color: black; } .loginbox span { color: black; font-weight: 500; font-size: 18px; } .loginbox input[type=text], .loginbox input[type=password] { height: 20px; border: none; border-radius: 4px; outline: none; } .loginbox input[type=button] { width: 40%; height: 24px; border: none; border-radius: 4px; margin: 0 auto; outline: none; } .loginbox .a { display: flex; margin: 20px auto; width: 45%; justify-content: space-between; } .loginbox .a a { color: white; } .loginbox .a a:hover { color: rgb(228, 221, 228); } 
邮箱简易发送系统
账号:

密码:

邮箱:



验证码:

【SpringBoot】SpringBoot使用mail实现登录邮箱验证_java如何实现邮箱验证码登录