最近做一个社区项目,发现很多地方都需要校验是否为用户本人,然后做了个邮箱验证分享给大家,当然也可以采用手机验证码。思想和邮箱验证码是类似的,只需要稍作修改。废话不多说直接上代码。
1.导入邮箱依赖
我这里是基于spring boot下的maven项目,导入pom依赖。用的是springboot2.2.2版本。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2.有关application.yaml配置
#邮件发送
spring:
mail:
username:XXXX@qq.com
#邮箱授权码,百度一下很简单
password: 授权码
host: smtp.qq.com
default-encoding: utf-8
#开启加密验证
properties:
mail:
smtp:
ssl:
enable: ture
3.创建一个工具类生成验证码
/**
* @Description TODO:邮箱验证码,采用SecureRandom真随机数
* @Author 郁郁201
* @Date 2020-01-20 17:03
* @Version 1.0
*/
public class VerCodeGenerateUtil {
//邮箱字符串提取,去除了容易混淆的几个字符比如0,o~
private static final String SYMBOLS = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
private static final Random RANDOM = new SecureRandom();
/**
* 生成4位随机验证码
* @return 返回4位验证码
*/
public static String getVerCode() {
char[] nonceChars = new char[4];
for (int index = 0; index < nonceChars.length; ++index) {
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
}
return new String(nonceChars);
}
}
4.发送邮件验证码
创建ScheduledExecutorService线程池(该线程池,将计时和多线程结合一起,perfect),以便于多用户获取验证码放入session并计时。ReslutTypeDto为返回前端的数据类型,VisitorStatusEmun为枚举类型,存放多种结果操作,下面附有注释,可自行替换。
//创建线程池对象
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
//这个是我用户Service实现类可以自行替换
@Autowired
UserServiceImpl userServiceImpl;
//这个是邮件类,必须要导入哦
@Autowired
JavaMailSenderImpl mailSender;
@GetMapping("/reg/sendEmail")
@ResponseBody
public ReslutTypeDto sendEmail(String email,HttpServletRequest request){
HttpSession session = request.getSession();
//验证码
String verCode = VerCodeGenerateUtil.getVerCode();
//发送时间 --这里自己写了一个时间类,格式转换,用于邮件发送
String time = DateUtils.date2String(new Date(), "yyyy-MM-dd hh:mm:ss");
Map<String,String> map = new HashMap<>();
map.put("code",verCode);
map.put("email",email);
//验证码和邮箱,一起放入session中
session.setAttribute("verCode",map);
Map<String,String> codeMap = (Map<String,String>) session.getAttribute("verCode");
//创建计时线程池,到时间自动移除验证码
try {
scheduledExecutorService.schedule(new Thread(()->{
if(email.equals(codeMap.get("email"))){
session.removeAttribute("verCode");
}
}), 5*60, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
}
//一下为发送邮件部分
MimeMessage mimeMessage = null;
MimeMessageHelper helper = null;
try {
//发送复杂的邮件
mimeMessage = mailSender.createMimeMessage();
//组装
helper= new MimeMessageHelper(mimeMessage, true);
//邮件标题
helper.setSubject("【Share社区】 注册账号验证码");
//因为设置了邮件格式所以html标签有点多,后面的ture为支持识别html标签
//想要不一样的邮件格式,百度搜索一个html编译器,自我定制。
helper.setText("<h3>\n" +
"\t<span style=\"font-size:16px;\">亲爱的用户:</span> \n" +
"</h3>\n" +
"<p>\n" +
"\t<span style=\"font-size:14px;\"> </span><span style=\"font-size:14px;\"> <span style=\"font-size:16px;\"> 您好!您正在进行邮箱验证,本次请求的验证码为:<span style=\"font-size:24px;color:#FFE500;\"> "+verCode+"</span>,本验证码5分钟内有效,请在5分钟内完成验证。(请勿泄露此验证码)如非本人操作,请忽略该邮件。(这是一封自动发送的邮件,请不要直接回复)</span></span>\n" +
"</p>\n" +
"<p style=\"text-align:right;\">\n" +
"\t<span style=\"background-color:#FFFFFF;font-size:16px;color:#000000;\"><span style=\"color:#000000;font-size:16px;background-color:#FFFFFF;\"><span class=\"token string\" style=\"font-family:"font-size:16px;color:#000000;line-height:normal !important;background-color:#FFFFFF;\">Share社区</span></span></span> \n" +
"</p>\n" +
"<p style=\"text-align:right;\">\n" +
"\t<span style=\"background-color:#FFFFFF;font-size:14px;\"><span style=\"color:#FF9900;font-size:18px;\"><span class=\"token string\" style=\"font-family:"font-size:16px;color:#000000;line-height:normal !important;\"><span style=\"font-size:16px;color:#000000;background-color:#FFFFFF;\">"+time+"</span><span style=\"font-size:18px;color:#000000;background-color:#FFFFFF;\"></span></span></span></span> \n" +
"</p>",true);
//收件人
helper.setTo(email);
//发送方
helper.setFrom(我的邮箱);
try {
//发送邮件
mailSender.send(mimeMessage);
} catch (MailException e) {
//邮箱是无效的,或者发送失败
return new ReslutTypeDto(VisitorStatusEmun.Email_Invalid);
}
} catch (MessagingException e) {
//发送失败--服务器繁忙
return new ReslutTypeDto(VisitorStatusEmun.Server_Busy);
}
//发送验证码成功
return new ReslutTypeDto(VisitorStatusEmun.Send_Email_Captcha_OK);
}
5.接收并使用邮件验证码
最后一步注册时使用验证码,获取了前端三个参数,邮箱(username),密码,验证码(vercode)。
//这里我采用的是email作为username
@PostMapping("/reg")
@ResponseBody
public ReslutTypeDto reg(String username,
String password,
String verCode,
HttpServletRequest httpServletRequest){
HttpSession session = httpServletRequest.getSession();
Map<String,String> codeMap = (Map<String,String>)session.getAttribute("verCode");
String code = null;
String email = null;
try {
code = codeMap.get("code");
email = codeMap.get("email");
} catch (Exception e) {
//验证码过期,或未找到 ---验证码无效
return new ReslutTypeDto(VisitorStatusEmun.Email_Captcha_Invalid);
}
//验证码判断
if (!verCode.toUpperCase().equals(code) || !username.equals(email)) {
return new ReslutTypeDto(VisitorStatusEmun.Email_Captcha_Fail);
}
//验证码使用完后session删除
session.removeAttribute("verCode");
User user = userServiceImpl.findUserByName(username);
//用户名是否可用
if (user!=null){
//返回,该用户)(username)已被注册过
return new ReslutTypeDto(VisitorStatusEmun.Account_Registered);
}
//数据库插入数据
Integer integer = userServiceImpl.addUser(username, password);
//是否插入数据成功
if (integer==null||!integer.equals(1)){
//返回注册失败
return new ReslutTypeDto(VisitorStatusEmun.Register_Fail);
}
//返回注册成功
return new ReslutTypeDto(VisitorStatusEmun.Register_OK);
}
6.效果展示
7.思想总结
验证码运用在项目中的还是挺简单的(需要全套源码评论区留邮箱哦),主要掌握核心思想,就是验证码的存放,移除。我这采用的session存放,当然大家也可已采用其他方式。以上就是发送邮箱验证码全过程了,如有纰漏还请多多指教~