|
@@ -82,12 +82,18 @@ public class SwitchableCaptchaSmsHandler implements CaptchaSmsHandler {
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public SmsSession send(@NonNull String mobile) {
|
|
public SmsSession send(@NonNull String mobile) {
|
|
|
|
+ // 短信验证码发送频率限制
|
|
|
|
+ String lock = "sms:captcha:interval:" + mobile;
|
|
|
|
+ String secret = RedisUtils.tryLock(lock, Duration.ofSeconds(this.properties.getInterval()));
|
|
|
|
+ if (StringUtils.isEmpty(secret)) {
|
|
|
|
+ throw new ResourceUnavailableException(TemplateSmsHandler.SMS_SEND_FREQUENTLY, "短信发送过于频繁,请稍后再试");
|
|
|
|
+ }
|
|
|
|
+
|
|
// 如果目标手机号属于测试手机号,则直接返回配置的验证码信息,否则获取真实的验证码
|
|
// 如果目标手机号属于测试手机号,则直接返回配置的验证码信息,否则获取真实的验证码
|
|
- String test = this.lookupTestingCaptcha(mobile);
|
|
|
|
- boolean testing = StringUtils.nonEmpty(test);
|
|
|
|
- String code = testing ? test : String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));
|
|
|
|
- Duration duration = Duration.ofSeconds(this.properties.getInterval());
|
|
|
|
- return RedisUtils.tryLockAround("sms:interval:" + mobile, duration, () -> {
|
|
|
|
|
|
+ try {
|
|
|
|
+ String test = this.lookupTestingCaptcha(mobile);
|
|
|
|
+ boolean testing = StringUtils.nonEmpty(test);
|
|
|
|
+ String code = testing ? test : String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));
|
|
String key = this.key(mobile), token = StringUtils.uuid();
|
|
String key = this.key(mobile), token = StringUtils.uuid();
|
|
Captcha captcha = Captcha.builder().token(token).code(code).mobile(mobile).build();
|
|
Captcha captcha = Captcha.builder().token(token).code(code).mobile(mobile).build();
|
|
if (!testing) {
|
|
if (!testing) {
|
|
@@ -95,9 +101,11 @@ public class SwitchableCaptchaSmsHandler implements CaptchaSmsHandler {
|
|
}
|
|
}
|
|
this.redisTemplate.opsForValue().set(key, captcha, this.properties.getExpiration(), TimeUnit.SECONDS);
|
|
this.redisTemplate.opsForValue().set(key, captcha, this.properties.getExpiration(), TimeUnit.SECONDS);
|
|
return SmsSession.builder().token(token).expiration(this.properties.getExpiration()).build();
|
|
return SmsSession.builder().token(token).expiration(this.properties.getExpiration()).build();
|
|
- }, () -> {
|
|
|
|
- throw new ResourceUnavailableException(TemplateSmsHandler.SMS_SEND_FREQUENTLY, "短信发送过于频繁,请稍后再试");
|
|
|
|
- });
|
|
|
|
|
|
+ } catch (RuntimeException e) {
|
|
|
|
+ // 保证验证码发送失败场景下及时释放锁
|
|
|
|
+ RedisUtils.unlock(lock, secret);
|
|
|
|
+ throw e;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|