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
输入错误的验证码
输入正确的验证码
关注公众号 「全栈技术部」
,不断学习更多有趣的技术知识。
![](https://gitee.com/shizidada/moose-resource/raw/master/blog/qrcode_430.jpg)