邮箱验证码
邮箱验证码
在注册账号、重置密码、验证身份等场景下,需要利用验证码验证用户身份,在确认用户操作后再执行下一步操作。
拆解为关键节点:
- 生成验证码
- 设计逻辑验证验证码有效期
- 利用SMTP服务发送邮件
- 验证验证码有效性
生成验证码
简单的六位随机数
private String genCode(){
//生成随机数6位
Random random = new Random();
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < 6; i++) {
int number = random.nextInt(10);
buffer.append(number);
}
return String.valueOf(buffer);
}
存储验证码
向redis中保存邮箱、发送时间和验证码,便于后续使用的时候验证。
@PostMapping("/registerCode")
public Response<Void> sendCode(@RequestBody @Valid RegisterCodeDTO registerDTO) throws MessagingException {
//省略GoogleChapta相关代码
Users usersParams = new Users();
usersParams.setEmail(registerDTO.getEmail());
//验证用户是否重复
Users usersRet = usersService.queryByUsers(usersParams);
if (usersRet != null){
return new Response.Builder<Void>()
.code(ResponseCode.USERS_EMAIL_ALREADY_REGISTER)
.build();
}
//生成验证码
String code = genCode();
long now = new Date().getTime();
String token = CryptoUtil.encodeMD5Hex(registerDTO.getEmail()+now);
//发送邮件
sendCode(registerDTO.getEmail(),code);
//把邮箱-时间-验证码存入redis
stringRedisTemplate.opsForValue().set(RedisServicePreFix.USER_SERVICE +
RedisEntityPreFix.REGISTER_CODE + token,code,300,TimeUnit.SECONDS);
return new Response.Builder<Void>()
.code(ResponseCode.COMMON_SUCCESS)
.message("发送成功, 请登录邮箱及时查看")
.build();
}
发送验证码
代码如下
private void sendCode(String email,String code) throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
helper.setFrom("xx工作室<"+mailUsername+">");
helper.setTo(email);
helper.setSubject("验证码");
Map<String,Object> map = new HashMap<>();
map.put("email",email);
map.put("code",code);
helper.setText(emailUtil.builderContent("code.html",map),true);
mailSender.send(mimeMessage);
}
MimeMessageHelper
类是SpringMail组件提供的,可以用模板html填充的方式组件邮件内容,然后直接发送即可。对接邮件服务器相关配置在Spring配置文件中,这种敏感信息建议从环境变量读取,以防一不小心传给别人然后忘了或者不小心传到Github了。
#邮件测试
spring.mail.username=${MAIL_USER:}
spring.mail.password=${MAIL_PASSWORD:}
spring.mail.properties.mail.smtp.auth=true
spring.mail.protocol=smtps
spring.mail.properties.mail.ssl.enable=true
#spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
#spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.default-encoding=UTF-8
spring.mail.port=465
spring.mail.host=${MAIL_HOST:}
验证验证码有效性
这里直接写一段Lua,去Redis里面读出结果对比一下就行。
private Long checkCode(String key, String code) {
String codeLua = "local code=redis.call('get',KEYS[1]) "+
"if code==false then "+
"return 0 "+
"end "+
"if code~=ARGV[1] then "+
"return 0 "+
"end "+
"redis.call('del',KEYS[1]) "+
"return 1 ";
DefaultRedisScript<Long> codeScript = new DefaultRedisScript<>(codeLua, Long.class);
return stringRedisTemplate.execute(codeScript,
Collections.singletonList(key),
code
);
}
License:
CC BY 4.0