关于springboot:springboot-实现邮箱找回密码使用到redis-stmp

51次阅读

共计 8026 个字符,预计需要花费 21 分钟才能阅读完成。

背景

小组我的项目要做一个邮箱找回明码的性能。须要用到 redis

大略流程如下:

  1. 第一步,用户填写邮箱,并点击“获取验证码”,浏览器发送申请,调用获取验证码接口。而后,服务端依据邮箱,生成验证码,发送验证码给这个邮箱,并将验证码和邮箱和有效期放到 redis/ 内存中
  2. 用户在邮箱中查到验证码后→填写到登录界面→点击登录→前端申请登录接口,携带邮箱和验证码参数。
  3. 服务器收到申请后,到 redis 中取到这个邮箱对应的信息→校验验证码是否正确,并验证是否过期,如果验证码正确且没有过期,则失常登录。

Redis

先介绍一下 redis

Redis 是齐全开源收费的,,是一个高性能的key-value 非关系性数据库(NoSql)。

Redis 与其余 key – value 缓存产品有以下三个特点:

  • Redis 反对数据的长久化,能够将内存中的数据保留在磁盘中,重启的时候能够再次加载进行应用。
  • Redis 不仅仅反对简略的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。

Redis 能够存储键与 5 种不同数据结构类型之间的映射,这 5 种数据结构类型别离为 String(字符串)、List(列表)、Set(汇合)、Hash(散列)和 Zset(有序汇合)。

下载 Redis

间接拜访 github 网址:https://github.com/MSOpenTech…,
如下图所示:

我下载的是 windows 版本

启动 Redis

redis.windows.conf 为 redis 配置文件,相干参数能够在这里配置,如:端口等,我这里应用默认参数,暂不批改,默认端口为 6379。双击 redis-server.exe 启动,则呈现如下图所示,则启动胜利。

SpringBoot 中应用 Redis

在我的项目的 pom.xml 中增加如下:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

application.yml 中配置如下

  # redis 配置
  redis:
    # 地址
    host: localhost
    # 端口,默认为 6379
    port: 6379
    # 数据库索引
    database: 0
    # 明码
    password:
    # 连贯超时工夫
    timeout: 10s
    lettuce:
      pool:
        # 连接池中的最小闲暇连贯
        min-idle: 0
        # 连接池中的最大闲暇连贯
        max-idle: 8
        # 连接池的最大数据库连接数
        max-active: 8
        # #连接池最大阻塞等待时间(应用负值示意没有限度)max-wait: -1ms

编写 Redis 操作工具类

咱们对 redis 操作须要用到RedisTemplate

RedisTemplate 是简化 Redis 数据库拜访代码的助手类,也是 Spring Data Redis 对 Redis 反对的核心类。

咱们这里将 RedisTemplate 实例包装成一个工具类,便于对 redis 进行数据操作。

创立 spring redis 工具类

@Component
public class RedisCache {
    @Autowired
    public RedisTemplate redisTemplate;
    
    // redis 序列化器 类型为 string
    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        this.redisTemplate = redisTemplate;
    }

}

上面编写工具办法

1. 设置缓存对象

  /**
     * 缓存根本的对象,Integer、String、实体类等
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param timeout  工夫
     * @param timeUnit 工夫颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

比如说咱们要将验证码存入 redis,就能够这么做

// 验证码存入 redis 并设置过期工夫
redisCache.setCacheObject("mail_code:" + username, verifyCode, 5, TimeUnit.MINUTES);

这里咱们设置

key 为 mail_code: + username,示意某个用户的邮箱验证码

value 为 verifycode , 示意验证码

timeout 为 5, timeUnit 为 MINUTES,示意过期工夫为 5 分钟。

2. 取得缓存的根本对象。

/**
     * 取得缓存的根本对象。*
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key) {ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }

比方应用如下: 依据 key 获取 value

String verifyCode = redisCache.getCacheObject("mail_code: + usrname);

3. 设置无效工夫

/**
     * 设置无效工夫
     *
     * @param key     Redis 键
     * @param timeout 超时工夫
     * @param unit    工夫单位
     * @return true= 设置胜利;false= 设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit) {return redisTemplate.expire(key, timeout, unit);
    }

比方咱们在用户胜利应用完该验证码后,想将该验证码设置为过期:

// 将验证码过期
redisCache.expire("mail_code: + usrname, 0, TimeUnit.SECONDS);

示意该键值对会在 0 秒后过期。

4. 删除对象

/**
 * 删除单个对象
 *
 * @param key
 */
public boolean deleteObject(final String key) {return redisTemplate.delete(key);
}

除这几个罕用的外,还编写了几个类,比方依据 key, 写入新的值,笼罩旧的值等,在此就不一一列出。

同时咱们还能够编写,对 Set,Hash,Map,List 类型的操作工具类,然而我没有用到,所以没有编写。

应用邮箱发送验证码

这里用到 SMTP 服务

SMTP

SMTP 的全称是“Simple Mail Transfer Protocol”,即简略邮件传输协定。

什么是 SMTP?
SMTP 代表简略邮件传输协定,它是电子邮件发送的行业标准协议。
应用 SMTP,你能够从邮件客户端(如 Microsoft Outlook)向接管电子邮件服务器发送、中继或转发邮件。发件人将应用 SMTP 服务器来执行发送电子邮件的过程。
在思考是应用 SMTP 还是 IMAP 时要记住的要害是 SMTP 是对于发送电子邮件的。因而,如果你心愿在你的应用程序中启用电子邮件发送,那么你须要持续应用 SMTP over IMAP。

什么是 IMAP?
如果 SMTP 是对于发送的,那么 IMAP 是什么?
简而言之,IMAP(Internet 拜访音讯协定)是一种电子邮件协定,用于治理和检索来自接管服务器的电子邮件音讯。
因为 IMAP 解决音讯检索,因而你将无奈应用 IMAP 协定发送电子邮件。相同,IMAP 将用于接管音讯。

除了 IMAP,还有另一种用于接管电子邮件的协定 — 称为 POP3。感兴趣能够查一下

简略来说, SMTP 用于发送,IMAP 用于接管

因为只发送,所以我只用到 SMTP。

发件邮箱要求

这里应用的是 163 邮箱,

1. 设置 POP3/SMTP/IMAP

2. 开启服务
开启会让设置受权码,受权码要记牢!前面须要写在配置里

3. 查看服务器地址
再往下翻有 163 SMTP 服务器地址 等下须要配置在 application.yml 中

代码实现

1.pom 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2.application.yml 配置

  # 配置邮箱服务器,账号密码等
  mail:
    host: smtp.163.com
    username: xxx@163.com
    password: xxx
    port:
    default-encoding: utf-8
    protocol: smtp
    properties:
      mail.smtp.auth: true
      mail.smtp.starttls.enable: true
      mail.smtp.starttls.required: true
      mail.smtp.socketFactory.port: 465
      mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory
      mail.smtp.socketFactory.fallback: false

3. 获取验证码 controller

@RestController
@RequestMapping("/mail")
public class MailController {

    @Autowired
    private MailService mailService;

    /**
     * 获取重置明码的验证码
     */
    @GetMapping("/getCode")
    public void getCode(@RequestParam String staffNumber, @RequestParam String mailAddress){mailService.getCode(staffNumber,mailAddress);
    }
}

4. ServiceImpl 层

@Service
public class MailServiceImpl implements MailService {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private JavaMailSender mailSender;

    @Autowired
    private UserRepository userRepository;

    @Value("${spring.mail.username}")
    private String mailUserName;

    @Value("${mail.code.overtime}")
    private Integer overtime; // 过期工夫

 /**
     * 获取重置明码的验证码
     *
     * @param username 用户账号
     * @param mailAddress 用户邮箱
     * @return
     */
    @Override
    public void getCode(String username, String mailAddress) {
        // 非空校验
        if (null == username || "".equals(username)) throw new EntityNotFoundException(" 账号不能为空!");
        if (null == mailAddress || "".equals(mailAddress)) throw new EntityNotFoundException(" 邮箱不能为空!");

        // 账号存在校验
        User user = userRepository.findByUsernameAndDeletedIsFalse(username);
        if (null == user) throw new EntityNotFoundException("账号不存在!");
        if (!user.getPhone().equals(mailAddress)) throw new EntityNotFoundException("输出邮箱和预留邮箱不统一!");

  
        verifyCode = String.valueOf(new Random().nextInt(899999) + 100000);// 生成短信验证码
        
        // 验证码存入 redis 并设置过期工夫
        redisCache.setCacheObject(Constants.MAIL_CODE_KEY + username, verifyCode, overtime, TimeUnit.MINUTES);

        // 编写邮箱内容
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("<html><head><title></title></head><body>");
        stringBuilder.append("您好 <br/>");
        stringBuilder.append("您的验证码是:").append(verifyCode).append("<br/>");
        stringBuilder.append("您能够复制此验证码并返回至设施管理系统找回明码页面,以验证您的邮箱。<br/>");
        stringBuilder.append("此验证码只能应用一次,在");
        stringBuilder.append(overtime.toString());
        stringBuilder.append("分钟内无效。验证胜利则主动生效。<br/>");
        stringBuilder.append("如果您没有进行上述操作,请疏忽此邮件。");
        MimeMessage mimeMessage = mailSender.createMimeMessage();

        // 发件配置并发送邮件
        try {MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
            // 这里只是设置 username 并没有设置 host 和 password,因为 host 和 password 在 springboot 启动创立 JavaMailSender 实例的时候曾经读取了
            mimeMessageHelper.setFrom(mailUserName);
            mimeMessageHelper.setTo(mailAddress);
            mimeMessage.setSubject("邮箱验证 - 重置明码");
            mimeMessageHelper.setText(stringBuilder.toString(), true);
            mailSender.send(mimeMessage);
        } catch (MessagingException e) {e.printStackTrace();
        }
    }

次要逻辑:

1. 数据校验
次要校验前台传入数据非空,以及 user 账号是否存在,输出邮箱和预留邮箱是否统一等

// 非空校验
if (null == username || "".equals(username)) throw new EntityNotFoundException(" 账号不能为空!");
if (null == mailAddress || "".equals(mailAddress)) throw new EntityNotFoundException(" 邮箱不能为空!");

// 账号存在校验
User user = userRepository.findByUsernameAndDeletedIsFalse(username);
if (null == user) throw new EntityNotFoundException("账号不存在!");
if (!user.getPhone().equals(mailAddress)) throw new EntityNotFoundException("输出邮箱和预留邮箱不统一!");

2. 验证码存入 redis
首先查看该 key,是否存在于 redis 缓存中。

 verifyCode = String.valueOf(new Random().nextInt(899999) + 100000);// 生成短信验证码
// 验证码存入 redis 并设置过期工夫
redisCache.setCacheObject(Constants.MAIL_CODE_KEY + username, verifyCode, overtime, TimeUnit.MINUTES);

3. 编写邮件内容
代码如上,此处省略

4. 发送并配置邮件
这里用到了 JavaMailSender 来发送邮件。

最晚期的时候会应用 JavaMail 相干 api 来写发送邮件的相干代码

spring 推出了 JavaMailSender 简化了邮件发送的过程,

在之后 springboot 对此进行了封装就有了当初的 spring-boot-starter-mail

 // 发件配置并发送邮件
        try {MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
            // 这里只是设置 username 并没有设置 host 和 password,因为 host 和 password 在 springboot 启动创立 JavaMailSender 实例的时候曾经读取了
            mimeMessageHelper.setFrom(mailUserName);
            mimeMessageHelper.setTo(mailAddress);
            mimeMessage.setSubject("邮箱验证 - 重置明码");
            mimeMessageHelper.setText(stringBuilder.toString(), true);
            mailSender.send(mimeMessage);
        } catch (MessagingException e) {e.printStackTrace();
        }
  1. 验证验证码正确性

从 redis 中获取该验证码,若从 redis 中获取值为 null, 则验证码曾经过期

String cacheCode = redisCache.getCacheObject(Constants.MAIL_CODE_KEY + num); // 获取缓存中该账号的验证码
if (cacheCode == null) {throw new EntityNotFoundException("验证码已过期,请从新获取!");
}

// 验证码正确性校验
if (!cacheCode.equals(codes)) {throw new EntityNotFoundException("验证码谬误!");
}

参考
https://www.cnblogs.com/fonks…
https://www.cnblogs.com/equal…
https://ost.51cto.com/posts/1262

正文完
 0