日程管理项目作为一个前后端分离的项目,其后端部分有数据存储与处理的作用,承担项目运转的核心。身份验证部分则是保障数据安全的重要过程。该部分以Auth和AuthService类为核心,配合其余类辅助完成。本文意在简要说明该部分的实现过程。
具体接口及实现过程如下:
1.注册("/auth/register"):
注册需要用户名,密码,邮箱,邮箱验证码(由获取验证码接口获取,于后文说明)四个字段,当邮箱验证码错误时服务器会拒绝这个请求并返回报错。实现方式如下:
if(!Objects.equals(info.code, redisService.getValue(info.email))) throw new InvalidCode();
在通过验证之后,服务端会检测请求的非法字段,如有非法字段,会向客户端报错,若没有,则会将用户信息添加到数据库中,完成注册。
2.登录("/auth/login")
登录逻辑比较简单,获取前端输入的用户名和密码,和数据库内容比较,如果是合法的用户,则赋予其登录态,否则,返回异常。
在登录的过程中,同时支持以邮箱作为用户名,解决了用户可能遗忘用户名的问题。
3.获取邮箱验证码("/auth/getCode")
验证码是很重要的功能,在注册,找回密码都有它的用武之地。此接口用于获取一个验证码中。在获取过后,服务端会将验证码与邮箱作为一个键值对存储到redis中,在执行需要验证码的操作的时候,服务器会从redis中读取邮箱,如果它的验证码是正确的,则允许操作,否则,会返回异常。
验证码的发送通过smtp服务进行,首先要创建一个smtp发送邮件的类:
public class MailUtil {
public void sendMail(String receiver,String subject,String message) throws MessagingException {
String sender = "YOUR MAILBOX";
String password = "YOUR PASSWORD";
String host = "smtp.office365.com";
int port = 587;
Properties props = new Properties();
props.setProperty("mail.debug", "true"); //false
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.transport.protocol", "smtp");
props.put("mail.smtp.starttls.enable", "true");
// 设置环境信息
Session session = Session.getInstance(props);
// 创建邮件对象
MimeMessage msg = new MimeMessage(session);
// 设置发件人
msg.setFrom(new InternetAddress(sender));
// 设置收件人
msg.addRecipient(Message.RecipientType.TO, new InternetAddress(receiver));
// 设置邮件主题
msg.setSubject(subject);
Multipart multipart = new MimeMultipart();
MimeBodyPart textPart = new MimeBodyPart();
textPart.setText(message);
multipart.addBodyPart(textPart);
msg.setContent(multipart);
//得到邮差对象
Transport transport = session.getTransport();
// 连接邮件服务器
// transport.connect(sender, password);
transport.connect(host, port, sender, password);
// 发送邮件
transport.sendMessage(msg, new Address[]{new InternetAddress(receiver)});
// 关闭连接
transport.close();
}
}
之后,便可以调用这个类实现发送邮件。
邮件的发送带来一个重要的问题:恶意脚本频繁发送邮件,浪费服务器资源同时对用户造成骚扰。
针对这个问题,我的解决策略如下:
·在发送邮件时,将邮箱和验证码这一键值对在redis中存储并设置一定有效期,在验证码被使用后删除这一键值对。
·在每次发送邮件时,检测redis中此邮箱是否保留有效验证码,如有,则拒绝这次发送邮件
该部分代码实现方案如下:
public void sendEmail(String email) throws MessagingException,ResponseError {
//检查redis中是否还有有效验证码,如有,则拒绝发送邮件并报错
if(redisService.getValue(email)!=null) throw new TooManyMailSends();
int code=(int)(Math.random()*999999);
//记录日志,发送验证码,并存储到redis
log.info("Send Email to "+email+"with code "+code+" at "+dateToStamp.stampToDate(System.currentTimeMillis()));
redisService.setValue(email,String.valueOf(code),150);
mailUtil.sendMail(email,"邮箱验证","您的验证码为:"+code+"\n该验证码120秒内有效");
}
4.修改与重置密码
此部分用于帮助用户在遗忘或泄露密码时做出应对。通过对原密码或者对邮箱的验证,完成修改密码的功能