我们在实现登录注册的时候,常常用到了短信验证码校验,下面给分享下代码
首先maven 导入jar包
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.2.8</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.1.0</version>
</dependency>
然后编写代码如下
@Slf4j
@Service
public class AliyunSmsServiceImpl implements ISmsService {
@Autowired
private AliyunSmsProperties aliyunSmsProperties;
@Autowired
private RedisTemplate<String, String> smsRedisTemplate;
private Random random = new Random(47);
@Override
public Msg send(String mobile) {
Msg<Object> msg = new Msg<>();
try {
// 检测是否发送过验证码
if (this.smsRedisTemplate.hasKey(aliyunSmsProperties.getKeyPrefix() + mobile)) {
// 获取验证码有效期
Long currentExpireTime = this.smsRedisTemplate.boundValueOps(aliyunSmsProperties.getKeyPrefix() + mobile).getExpire();
// 获取重试间隔
Integer retryInterval = aliyunSmsProperties.getRetryInterval();
// 获取有效期
Integer totalExpireTime = aliyunSmsProperties.getExpireTime();
if (retryInterval + currentExpireTime > totalExpireTime) {
msg.setMsg("请勿频繁获取验证码,重获验证码获取最小间隔" + retryInterval + "秒");
return msg;
}
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < aliyunSmsProperties.getCodeLength(); i++) {
sb.append(random.nextInt(9));
}
String code = sb.toString();
//设置超时时间-可自行调整
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化ascClient需要的几个参数
//短信API产品名称
final String product = "Dysmsapi";
//短信API产品域名
final String domain = "dysmsapi.aliyuncs.com";
//替换成你的AK
//你的accessKeyId,参考本文档步骤2
final String accessKeyId = aliyunSmsProperties.getAccessKeyId();
//你的accessKeySecret,参考本文档步骤2
final String accessKeySecret = aliyunSmsProperties.getAccessKeySecret();
//初始化ascClient,暂时不支持多region
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId,
accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为20个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
request.setPhoneNumbers(mobile);
//必填:短信签名-可在短信控制台中找到
request.setSignName(aliyunSmsProperties.getSignName());
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(aliyunSmsProperties.getTemplateCode());
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
// request.setTemplateParam("{\"customer\":\"" + mobile + "\"}");
request.setTemplateParam("{\"code\":\"" + code + "\"}");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
// request.setOutId("yourOutId");
//请求失败这里会抛ClientException异常
SendSmsResponse response = acsClient.getAcsResponse(request);
log.debug("发送短信验证码结果:{}", JSON.toJSONString(response));
if (response.getCode() != null && response.getCode().equals("OK")) {
//请求成功
msg.setData(response.getBizId());
msg.setResult(EnError.DEFAULT);
log.debug("发送短信验证码成功,手机号码:{},验证码:{}", mobile, code);
this.smsRedisTemplate.opsForValue().set(aliyunSmsProperties.getKeyPrefix() + mobile, String.valueOf(code), aliyunSmsProperties.getExpireTime(), TimeUnit.SECONDS);
} else {
msg.setMsg(response.getMessage());
}
} catch (Exception e) {
log.error("发送短信验证码失败,{}", e.getMessage());
}
return msg;
}
/**
* 短信验证码校验
*
* @param mobile 手机号码
* @param code 短信验证码
* @return 业务消息
*/
@Override
public Msg verify(String mobile, String code) {
log.debug("短信验证码校验:mobile = [{}],code = [{}]", mobile, code);
Msg<Object> msg = new Msg<>();
try {
// 检测是否发送过验证码
if (!this.smsRedisTemplate.hasKey(aliyunSmsProperties.getKeyPrefix() + mobile)) {
msg.setMsg("未获取到验证码");
return msg;
}
String tempCode = this.smsRedisTemplate.opsForValue().get(aliyunSmsProperties.getKeyPrefix()+mobile);
if (!code.equals(tempCode)) {
msg.setMsg("验证码不匹配");
} else {
msg.setResult(EnError.DEFAULT);
}
} catch (Exception e) {
log.error("短信验证码校验失败,mobile = [{}],code = [{}],{}", mobile, code, e.getMessage());
}
return msg;
}
}
阿里云配置
@Component
@ConfigurationProperties(prefix = "sms.aliyun")
public class AliyunSmsProperties {
/**
* 验证码前缀
* 保存着Redis数据库中使用
*/
private String keyPrefix = "verify-code:";
/**
* 重试间隔:单位为秒
*/
private int retryInterval = 60;
/**
* 验证码有效期:单位为秒
*/
private int expireTime = 300;
/**
* 验证码长度
*/
private int codeLength = 4;
/**
* 你的accessKeyId
*/
private String accessKeyId = "";
/**
* 你的accessKeySecret
*/
private String accessKeySecret = "";
/**
* SignName
*/
private String signName = "";
/**
* SignName
*/
private String templateCode = "";
public String getKeyPrefix() {
return keyPrefix;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public int getRetryInterval() {
return retryInterval;
}
public void setRetryInterval(int retryInterval) {
this.retryInterval = retryInterval;
}
public int getExpireTime() {
return expireTime;
}
public void setExpireTime(int expireTime) {
this.expireTime = expireTime;
}
public int getCodeLength() {
return codeLength;
}
public void setCodeLength(int codeLength) {
this.codeLength = codeLength;
}
public String getAccessKeyId() {
return accessKeyId;
}
public void setAccessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId;
}
public String getAccessKeySecret() {
return accessKeySecret;
}
public void setAccessKeySecret(String accessKeySecret) {
this.accessKeySecret = accessKeySecret;
}
public String getSignName() {
return signName;
}
public void setSignName(String signName) {
this.signName = signName;
}
public String getTemplateCode() {
return templateCode;
}
public void setTemplateCode(String templateCode) {
this.templateCode = templateCode;
}
}
注意:第一个代码块中的 new Msg()及return msg 这些代码更改成自己的返回信息,验证码是存在redis 内的,如果您本地未使用redis 请忽略这篇文章,或者选择使用redis。