热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

短信验证码java_SpringBootOAuth2.0使用Redis保存短信验证码+AccessToken

上一篇:江景:SpringBootOAuth2.0使用短信验证码登录授权​zhuanlan.zhihu.com使用Redis缓存服务,将授权服务返回的短
801815362dfdd7b3c74f98f50e83c000.png

上一篇:

江景:SpringBoot OAuth2.0 使用短信验证码登录授权​zhuanlan.zhihu.com
eb6087a33caaf35f9b873f2c36892a84.png

使用 Redis 缓存服务,将授权服务返回的短信验证码和 access_token 保存到 redis 中。

添加 redis 依赖

org.springframework.bootspring-boot-starter-data-redis

application.yml 文件, 添加 redis 配置

spring:# redis 配置可以不写,默认就是如下redis:database: 0host: localhostport: 6379

修改 MooseAuthorizationServerConfiguration

  • 修改 TokenStore 为 RedisTokenStore # 将原来的 数据库存储 token 改为 redis存储

@Resource private RedisConnectionFactory redisConnectionFactory;@Bean
public TokenStore tokenStore() {// 基于 JDBC 实现,令牌保存到数据库//return new JdbcTokenStore(dataSource);// 基于 Redis 实现,令牌保存到 Redisreturn new RedisTokenStore(redisConnectionFactory);
}

启动服务

  • 访问 localhost:7000/oauth/token?grant_type=sms_code&client_id=client&client_secret=secret&phone=1537031501&smsCode=9876
  • 查看 redis 服务器数据,发现 access_token, refresh_token 已经保存到 redis 服务器中
cf85dd71baaecdaf58e063764facd1eb.png

继续改造

将原来短信验证码验证的逻辑从 redis 中取发送的短信验证码

  • 编写发送短信验证码接口
  • 将发送的短信验证码保存到 redis 中

@RestController
@RequestMapping(value = "/api/v1/sms")
@Slf4j
public class SmsCodeController {@Resourceprivate SmsCodeSenderService smsCodeSenderService;@PostMapping("/send")public R sendSmsCode(@Valid SmsCodeVO smsCodeVO, BindingResult result) {return R.ok(smsCodeSenderService.sendSmsCode(smsCodeVO));}
}

发送短信验证码核心逻辑

  • 具体可以查看 https://gitee.com/shizidada/moose/blob/master/src/main/java/com/moose/operator/web/service/impl/DefaultSmsCodeSenderServiceImpl.java

private void sendAndSaveSmsCode(SmsCodeVO smsCodeVO) {// 生成短信验证码String smsCode = RandomStringUtils.randomNumeric(6);String phoneNumber = smsCodeVO.getPhone();String smsType = smsCodeVO.getType();// reset save sms code to redisString smsCodeKey = String.format(CacheNameConstant.SMS_CODE_KEY, smsType, phoneNumber);// TODO: get sms code not expired return ?SmsCodeDTO smsCodeDTO = (SmsCodeDTO) redisTemplate.opsForValue().get(smsCodeKey);if (ObjectUtils.isNotEmpty(smsCodeDTO) && !smsCodeDTO.getExpired()) {return;}// sms code save dbSmsCodeDO smsCodeDO = new SmsCodeDO();smsCodeDO.setPhone(phoneNumber);smsCodeDO.setType(smsType);smsCodeDO.setCode(smsCode);smsCodeMapper.insertSmsCode(smsCodeDO);smsCodeDTO =new SmsCodeDTO(smsCode, smsType, SecurityConstant.SMS_TIME_OF_TIMEOUT);redisTemplate.opsForValue().set(smsCodeKey, smsCodeDTO, SecurityConstant.SMS_TIME_OF_TIMEOUT, TimeUnit.SECONDS);// mock, 真正发送短信可以使用 阿里云 sms log.info("phone number [{}] send sms code [{}]", phoneNumber, smsCode);}

修改 SmsCodeTokenGranter

  • 构造 SmsCodeTokenGranter Bean 时,传递 RedisTemplate,进行操作 redis
  • 具体查看
  • https://gitee.com/shizidada/moose/blob/master/src/main/java/com/moose/operator/web/security/granter/SmsCodeTokenGranter.java
  • https://gitee.com/shizidada/moose/blob/master/src/main/java/com/moose/operator/web/security/configure/MooseAuthorizationServerConfiguration.java

....
private RedisTemplate redisTemplate;public void setRedisTemplate(RedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}// 客户端提交的验证码String smsCode = parameters.get(CommonConstant.DEFAULT_PARAMETER_NAME_CODE_SMS);if (StringUtils.isBlank(smsCode)) {throw new BusinessException(ResultCode.SMS_CODE_IS_EMPTY);}//sms_loginString smsCodeKey =String.format(CacheNameConstant.SMS_CODE_KEY, "sms_login", phoneNumber);SmsCodeDTO smsCodeDTO = (SmsCodeDTO) redisTemplate.opsForValue().get(smsCodeKey);// 获取服务中保存的用户验证码, 在生成好后放到缓存中if (ObjectUtils.isEmpty(smsCodeDTO) || smsCodeDTO.getExpired()) {throw new BusinessException(ResultCode.SMS_CODE_ERROR);}String smsCodeCached = smsCodeDTO.getCode();if (!StringUtils.equals(smsCode, smsCodeCached)) {throw new BusinessException(ResultCode.SMS_CODE_ERROR);}// 验证通过后从缓存中移除验证码 etc...redisTemplate.expire(smsCodeKey, 0, TimeUnit.SECONDS);// 客户端提交的手机号码AccountDTO accountDTO = accountService.getAccountByPhone(phoneNumber);....

将 /api/v1/sms/send 添加到 anonymousAntPatterns 集合中,不需要授权访问

  • 具体查看 anonymousAntPatterns 集合
  • https://gitee.com/shizidada/moose/blob/master/src/main/java/com/moose/operator/web/security/configure/MooseResourceServerConfiguration.java

启动服务测试

发送短信

localhost:7000/api/v1/sms/send?phone=1537031501&type=sms_login

2eaadb0ef2525089aeb655bc502b3704.png
5d020c2a827d1f6f305f242c24f1c1f3.png

输入错误的验证码

4182103f62031a2fc24fe576f874a4a2.png

输入正确的验证码

6f25d604ea88ce07acc8d1242bdf8d2d.png



推荐阅读
  • 本文介绍了关系型数据库和NoSQL数据库的概念和特点,列举了主流的关系型数据库和NoSQL数据库,同时描述了它们在新闻、电商抢购信息和微博热点信息等场景中的应用。此外,还提供了MySQL配置文件的相关内容。 ... [详细]
  • Redis API
    安装启动最简启动命令行输入验证动态参数启动配置文件启动常用配置通用命令keysbdsize计算key的总数exists判断是否存在delkeyvalue删除指定的keyvalue成 ... [详细]
  • Redis的默认端口、数据库使用和多端口配置
    本文介绍了Redis的默认端口、数据库使用和多端口配置的方法。通过选择不同的数据库和使用flushdb命令可以实现对不同数据库的访问和清除数据。同时,本文还介绍了在同一台机器上启用多个Redis实例的方法,并讨论了配置认证密码的步骤和注意事项。 ... [详细]
  • SQL Server 2008 到底需要使用哪些端口?
    SQLServer2008到底需要使用哪些端口?-下面就来介绍下SQLServer2008中使用的端口有哪些:  首先,最常用最常见的就是1433端口。这个是数据库引擎的端口,如果 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 本文介绍了sqlserver云存储和本地存储的区别,云存储是将数据存储在网络上,方便查看和调用;本地存储是将数据存储在电脑磁盘上,只能在存储的电脑上查看。同时提供了几种启动sqlserver的方法。此外,还介绍了如何导出数据库的步骤和工具。 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • 本文介绍了Windows Vista操作系统中的用户账户保护功能,该功能是为了增强系统的安全性而设计的。通过对Vista测试版的体验,可以看到系统在安全性方面的进步。该功能的引入,为用户的账户安全提供了更好的保障。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 面试经验分享:华为面试四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试
    最近有朋友去华为面试,面试经历包括四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试。80%的人都在第一轮电话面试中失败,因为缺乏基础知识。面试问题涉及 ... [详细]
  • Ansibleplaybook roles安装redis实例(学习笔记二十九)
    1、相关redis参数:2、templatesredis.conf配置相关参数:daemonizeyespidfilevarrunredis_{{red ... [详细]
  • 缓存 分布式锁 Redis
    分布式锁现在Redis基本上没家公司都在使用,只是各自使用的场景不以,但Redis最出名的还是做为缓存服务器,提搞服务器的的吞吐量,下面我们来围绕这个作为缓存做一个总结今天的目标其 ... [详细]
author-avatar
手机用户2602931615
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有