Commit 7f75af6f authored by 于桐's avatar 于桐

新增接口,vcc定制无验证码发短信

parent fc3ffd1a
Pipeline #946 failed with stages
package cn.quantgroup.xyqb.controller.internal.user;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import cn.quantgroup.tech.util.TechEnvironment;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.controller.IBaseController;
import cn.quantgroup.xyqb.controller.external.sms.SmsController;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.service.sms.ISmsService;
import lombok.extern.slf4j.Slf4j;
/**
* 内部定制接口
*
* @author yutong
* @time 2021-04-28
*/
@Slf4j
@RestController
@RequestMapping("/innerapi/custom")
@Validated
public class InnerCustomController implements IBaseController {
private final static String RANDOM_CHARS = "0123456789";
@Autowired
private ISmsService smsService;
/**
* VCC定制 - 无极验,发送短信验证码
*
* @param phoneNo - 手机号
* @param registerFrom -
* @param deviceId -
* @param appName -
* @param smsMerchant - 短信模板/类型
* @see SmsController#sendVccSmsCode(String, String, String, String, String)
*/
@RequestMapping("/send_vcc_sms_code")
public JsonResult sendVccSmsCode(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom,
@RequestParam(required = false) String deviceId,
@RequestParam(required = false, defaultValue = "") String appName,
@RequestParam(required = false) String smsMerchant) {
log.info("VCC-越过极验发送验证码, phoneNo:{}, registerFrom:{}", phoneNo, registerFrom);
String randomCode = getRandomCode(Constants.SMS_CODE_LEN_6);
return smsService.sendVerificationCode2New(phoneNo, randomCode, deviceId, true, appName, smsMerchant, getIp());
}
private String getRandomCode(int count) {
if (TechEnvironment.isPro()) {
return RandomStringUtils.random(count, RANDOM_CHARS);
}
switch (count) {
case 6:
return "000000";
default:
return Constants.SUCCESS_CODE;
}
}
}
package cn.quantgroup.xyqb.service.sms;
import cn.quantgroup.sms.SmsSender;
import cn.quantgroup.xyqb.controller.external.sms.SmsController;
import cn.quantgroup.xyqb.model.JsonResult;
/**
* 短信发送服务
......@@ -54,4 +56,18 @@ public interface ISmsService {
*/
void deleteOnlyCodeFromCache(String phoneNo);
/**
* 新版本短信验证码
* 必须与SmsController#sendVerificationCode2New同步
* @param phoneNo - 手机号
* @param deviceId - 设备id
* @param isApp -
* @param appName -
* @param smsMerchant - 短信模板/类型
* @return
* @see SmsController#sendVerificationCode2New(String, String, String, boolean, String, String)
*/
JsonResult sendVerificationCode2New(String phoneNo, String randomCode, String deviceId, boolean b, String appName,
String smsMerchant, String clientIp);
}
......@@ -4,7 +4,12 @@ import cn.quantgroup.sms.MsgParams;
import cn.quantgroup.sms.SmsSender;
import cn.quantgroup.tech.util.TechEnvironment;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.sms.SmsMerchant;
import cn.quantgroup.xyqb.service.sms.ISmsService;
import cn.quantgroup.xyqb.util.DateUtils;
import cn.quantgroup.xyqb.util.IpUtil;
import cn.quantgroup.xyqb.util.ValidationUtil;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
......@@ -14,7 +19,11 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
......@@ -32,6 +41,17 @@ public class SmsServiceImpl implements ISmsService {
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> stringRedisTemplate;
private static final long EXPIRE_MINUTES = 10;
private static final String IMAGE_IP_COUNT = "image:ip";
private static final String IMAGE_PHONE_COUNT = "image:phone";
private static final String IMAGE_DEVICEID_COUNT = "image:deviceId:";
/** ip上限 */
private static final Long IP_MAX_PER_DAY = 5000L;
/** 手机号短信上限 */
private static final Long PHONE_MAX_PER_DAY = 20L;
/** 设备每天上限 */
private static final Long DEVICE_MAX_PER_DAY = 20L;
@Override
@Synchronized
public SmsSender getSmsSender() {
......@@ -147,5 +167,108 @@ public class SmsServiceImpl implements ISmsService {
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
stringRedisTemplate.delete(key);
}
@Override
public JsonResult sendVerificationCode2New(String phoneNo, String randomCode, String deviceId, boolean isApp, String appName, String smsMerchant, String clientIp) {
if (!ValidationUtil.validatePhoneNo(phoneNo)) {
return JsonResult.buildErrorStateResult("手机号格式有误", null);
}
log.info("请求短信新版本接口:phoneNo:{},deviceId:{},IP:{}", phoneNo, deviceId, clientIp);
// 手机号计数器
Long getPhoneVerificationCount = stringRedisTemplate.opsForHash().increment(Constants.REDIS_SMS_CODE_COUNT, phoneNo, 1);
stringRedisTemplate.expire(Constants.REDIS_SMS_CODE_COUNT, DateUtils.getSeconds(), TimeUnit.SECONDS);
// 设备号计数器
Long getDeviceVerificationCount = 0L;
if (StringUtils.isNotBlank(deviceId)) {
getDeviceVerificationCount = stringRedisTemplate.opsForHash().increment(Constants.REDIS_SMS_DEVICE_COUNT, deviceId, 1);
stringRedisTemplate.expire(Constants.REDIS_SMS_DEVICE_COUNT, DateUtils.getSeconds(), TimeUnit.SECONDS);
}
// IP计数器
Long getIPVerificationCount = 0L;
if (StringUtils.isNotBlank(clientIp)) {
getIPVerificationCount = stringRedisTemplate.opsForHash().increment(Constants.REDIS_SMS_IP_COUNT, clientIp, 1);
stringRedisTemplate.expire(Constants.REDIS_SMS_IP_COUNT, DateUtils.getSeconds(), TimeUnit.SECONDS);
}
// 手机号上限检查
if (getPhoneVerificationCount > PHONE_MAX_PER_DAY) {
log.info("您手机号已经达到获取今天短信验证码上限:phoneNo:{},count:{}", phoneNo, getPhoneVerificationCount);
return JsonResult.buildErrorStateResult("今天已获取20次短信验证码,请使用语音验证码或明天再试", null);
}
// 设备号上限检查
if (getDeviceVerificationCount > DEVICE_MAX_PER_DAY) {
log.info("您设备已经达到获取今天验证码上限:deviceId:{},count:{}", deviceId, getDeviceVerificationCount);
return JsonResult.buildErrorStateResult("您设备已经达到获取今天验证码上限", null);
}
// IP上限检查
if (!IpUtil.whiteOf(clientIp) && getIPVerificationCount > IP_MAX_PER_DAY) {
log.info("您当前ip已经达到获取今天短信验证码上限:ip:{},count:{}", clientIp, getIPVerificationCount);
return JsonResult.buildErrorStateResult("您当前ip已经达到获取今天短信验证码上限", null);
}
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
long expire = stringRedisTemplate.getExpire(key, TimeUnit.MINUTES);
if (expire >= EXPIRE_MINUTES - 1) {
log.info("sendVerificationCode2New1分钟内不能重复获取验证码:phoneNo:{},deviceId:{},ip:{}", phoneNo, deviceId, clientIp);
return JsonResult.buildErrorStateResult("1分钟内不能重复获取验证码", null);
}
String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", "");
List<String> newList = new ArrayList<>();
newList.add(randomCode);
MsgParams message = new MsgParams.Builder()
.typeList(Collections.singletonList(2))
.phoneNo(phoneNo)
.merchantId(SmsMerchant.of(smsMerchant).getMerchantId())
.contentId(SmsMerchant.of(smsMerchant).getContentId())
.uniqueId(uniqueId)
.contentArgs(Collections.singletonList(randomCode))
.channel(appName)
.build();
try {
this.getSmsSender().sendMsg(message);
stringRedisTemplate.opsForValue().set(key, uniqueId + ":" + randomCode, EXPIRE_MINUTES, TimeUnit.MINUTES);
//删除用户重置密码,多次错误逻辑
deleteRetSendCode(phoneNo);
if (isApp && needImageVlidate(clientIp, deviceId, phoneNo)) {
return JsonResult.buildSuccessResult("发送成功", uniqueId, 3L);
}
log.info("sendVerificationCode2New获取短信成功:phone:{},deviceId:{},ip:{}", phoneNo, deviceId, clientIp);
return JsonResult.buildSuccessResult("发送成功", uniqueId);
} catch (Exception e) {
log.error("发送短信验证码失败:phone:{},deviceId:{},ip:{}", phoneNo, deviceId, clientIp);
return JsonResult.buildErrorStateResult("发送失败", null);
}
}
/**
* 判断下次是否提示图形验证码
*
* @param clientIp
* @param deviceId
* @param phoneNo
* @return
*/
private boolean needImageVlidate(String clientIp, String deviceId, String phoneNo) {
boolean need = false;
String countIP = stringRedisTemplate.opsForValue().get(IMAGE_IP_COUNT + clientIp);
String countDeviceId = stringRedisTemplate.opsForValue().get(IMAGE_DEVICEID_COUNT + deviceId);
String countPhoneNo = stringRedisTemplate.opsForValue().get(IMAGE_PHONE_COUNT + phoneNo);
Long ip = StringUtils.isBlank(countIP) ? 1L : Long.valueOf(countIP);
Long devId = StringUtils.isBlank(countDeviceId) ? 1L : Long.valueOf(countDeviceId);
Long phNo = StringUtils.isBlank(countPhoneNo) ? 1L : Long.valueOf(countPhoneNo);
if (ip >= Constants.Image_Need_Count || devId >= Constants.Image_Need_Count || phNo >= Constants.Image_Need_Count) {
need = true;
}
return need;
}
/**
* 删除用户重置密码时短信验证错误
*
* @param phoneNo
*/
private void deleteRetSendCode(String phoneNo) {
String verificationCountKey = Constants.REDIS_VERIFICATION_COUNT + phoneNo;
stringRedisTemplate.opsForHash().delete(verificationCountKey, Constants.REDIS_VERIFICATION_COUNT);
}
}
......@@ -42,8 +42,6 @@ public class UserDetailServiceImpl implements IUserDetailService {
@Autowired
private IUserDetailRepository userDetailRepository;
@Autowired
private IUserRepository userRepository;
@Autowired
private IIdCardService idCardService;
@Resource
private ApplicationEventPublisher applicationEventPublisher;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment