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

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

上一篇: SpringBoot OAuth2.0 使用短信验证码登录授权

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

添加 redis 依赖

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

application.yml 文件, 添加 redis 配置

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

修改 MooseAuthorizationServerConfiguration

  • 修改 TokenStore 为 RedisTokenStore # 将原来的 数据库存储 token 改为 redis存储
@Resource private RedisConnectionFactory redisConnectionFactory;
  
@Bean
public TokenStore tokenStore() {
    // 基于 JDBC 实现,令牌保存到数据库
    //return new JdbcTokenStore(dataSource);
    // 基于 Redis 实现,令牌保存到 Redis
    return 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 服务器中

继续改造

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

  • 编写发送短信验证码接口
  • 将发送的短信验证码保存到 redis 中
@RestController
@RequestMapping(value = "/api/v1/sms")
@Slf4j
public class SmsCodeController {
  @Resource
  private 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 redis
    String 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 db
    SmsCodeDO 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<String, Object> redisTemplate;


public void setRedisTemplate(
      RedisTemplate<String, Object> 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_login
    String 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

输入错误的验证码

输入正确的验证码

关注公众号 「全栈技术部」,不断学习更多有趣的技术知识。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值