写在开头:本篇文章记录于22年4月23,一个暖洋洋的下午
实现功能
用户在注册时需要输入邮件并完成验证,方可进行完整注册。
逻辑实现
---->前端邮箱输入栏右侧加一个发送邮件按钮
--->点击按钮,携带邮箱向后端发起发送邮件的请求
--->后端接收请求,生成5位随机验证码,一方面将验证码作为邮件内容发送,另一方面将验证码写入redis并设置1分钟的有效期。
--->前端用户收到验证码,提交注册表单(包含验证码)
--->后端接收到注册表单,现拿表单里的邮箱去redis进行验证码效验,若reids已没有验证码,返回验证码已失效,用邮箱查到的验证码表单不一致,则返回验证码错误,若效验成功则进行后续的账号验证与数据库的写入
--->前端验证码失效,按钮就显示重新发送,成功则跳转至登录页面
技术栈
前端:vue2.X + vue-admin-template
后端:springboot+mybatis-plus+mysql+springSecurity+jwt+shiro
代码实现(碍于篇幅,只显示关键代码,建议去文末的gitee仓库地址拉取文件管理项目(前后端)的完整代码)
依赖引入:
<!--邮件服务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--thylemeaf模板引擎(用于邮件模板设置)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--java常用工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.13</version>
</dependency>
<!--邮件服务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
springboot配置
#redis配置
redis:
# 地址
host: 127.0.0.1
# 端口号
port: 6379
# 密码(默认为空)
password:
# 超时时间,单位毫秒
timeout: 3000
# 数据库编号
database: 0
# 配置lettuce
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 1
# 连接池中的最大空闲连接
max-idle: 6
# 连接池最大连接数(使用负值表示没有限制,不要配置过大,否则可能会影响redis的性能)
max-active: 10
# 连接池最大阻塞等待时间(使用负值表示没有限制);单位毫秒
max-wait: 1000
#关闭超时时间;单位毫秒
shutdown-timeout: 200
#发送验证邮件
mail:
protocol: smtp
host: smtp.qq.com
port: 465
#自己邮箱和协议密码(非邮箱密码)
username: *******
password: *******
default-encoding: utf-8
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
ssl:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
shiro配置
@Component
public class ShiroConfig {
@Bean
public RedisTemplate<String, Object> template(RedisConnectionFactory factory) {
// 创建RedisTemplate<String, Object>对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
// 定义Jackson2JsonRedisSerializer序列化对象
Jackson2JsonRedisSerializer<Object> jacksonSeial = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会报异常
om.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance ,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.WRAPPER_ARRAY);
jacksonSeial.setObjectMapper(om);
StringRedisSerializer stringSerial = new StringRedisSerializer();
// redis key 序列化方式使用stringSerial
template.setKeySerializer(stringSerial);
// redis value 序列化方式使用jackson
template.setValueSerializer(jacksonSeial);
// redis hash key 序列化方式使用stringSerial
template.setHashKeySerializer(stringSerial);
// redis hash value 序列化方式使用jackson
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
}
发送邮件的service类
@Service
public class EmailService {
@Value("${spring.mail.username}")
private String sendEmailName;
@Resource
private JavaMailSender javaMailSender;
@Resource
private TemplateEngine templateEngine;
@Resource
private RedisTemplate<String, Object> redisTemplate ;
//发送邮件
public void sendEmail(String confirm,String email) {
try {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage);
//设置邮件基本信息
mimeMessageHelper.setSubject("欢迎来到李同学的文件管理系统:个人账号注册");
mimeMessageHelper.setFrom(sendEmailName);
mimeMessageHelper.setTo(email);
mimeMessageHelper.setSentDate(new Date());
//设置邮件内容模板
Context context = new Context();
context.setVariable("confirm", confirm);
//使用thymeleaf的模板引擎
String text = templateEngine.process("email.html", context);
mimeMessageHelper.setText(text, true);
//发送邮件
javaMailSender.send(mimeMessage);
//将验证码写入redis并设置1分钟有效期
redisTemplate.opsForValue().set(email, confirm, 1, TimeUnit.MINUTES);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用的thymeleaf邮件模板(将该eamil.html放入resources/templates/下)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="${confirm}"></title>
</head>
<body>
<p>这是由李同学的文件上传与下载系统发送的邮件:请不要泄露你的激活码</p>
</br>
<p th:text="你的激活码为 +${confirm}">你的激活码为:${}</p>
</body>
</html>
用户注册的service
//用户注册
public Result register(VoUser voUser){
User user=new User();
if(voUser==null) return Result.fail("注册信息未填写完整");
String salt= RandomUtil.randomString(5);
String password = DigestUtil.md5Hex(voUser.getPassword()+salt);
//效验账户
QueryWrapper<User> query=new QueryWrapper<>();
query.eq("username", voUser.getUsername())
.or()
.eq("email", voUser.getEmail())
.or()
.eq("phone_num", voUser.getPhoneNum());
List<User> list = userService.list(query);
if(!list.isEmpty()) return Result.fail("邮箱或用户名或手机号已被注册");
//效验验证码,用前端传来的邮箱去redis中查询验证码
String confirm=(String) redisTemplate.opsForValue().get(voUser.getEmail());
if(confirm==null) return Result.fail("验证码已失效,请重新发送");
else {
if(!confirm.equals(voUser.getConfirm())) return Result.fail("验证码不正确");
}
//效验完毕,写入数据库
user.setUsername(voUser.getUsername());
user.setEmail(voUser.getEmail());
user.setPhoneNum(voUser.getPhoneNum());
user.setSalt(salt);
user.setPassword(password);
user.setRole("ROLE_admin");
userService.save(user);
return Result.succ("注册成功");
}
注册和发送邮件的controller
//发送邮件
@GetMapping("/sendEmail")
public Result sendEmail(String email){
//生成五位随机验证码,注入邮件,同时返回给前端由于验证
String confirm= RandomUtil.randomString(5);
emailService.sendEmail(confirm,email);
return Result.succ(confirm);
}
//注册用户
@RequestMapping("/register")
public Result register(@RequestBody VoUser voUser) {
return loginService.register(voUser);
}
效果展示
写在最后
本文主要展示了涉及邮件验证的核心代码,与springSecurity, jwt, 文件上传下载的代码均在仓库里
项目的完整代码在:gitee仓库地址
有用的话给个star~~~~