使用阿里大于的短信服务需要先去开通相应服务,具体过程:https://www.jb51.net/article/171902.htm,https://www.cnblogs.com/shubs/p/12092089.html
加依赖:
<!--阿里大于短信--> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.3</version> </dependency>
然后拿到下面几个参数:
1、密钥:AccessKeyId、AccessKeySecret
2、模板CODE
3、短信签名(2和3在阿里云官网设置)
可以先去官网的OpenAPI Explorer中测试是否成功:
信息填好发送返回成功即可
再去看看官网是怎么发送请求的:
import com.aliyuncs.CommonRequest; import com.aliyuncs.CommonResponse; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.exceptions.ServerException; import com.aliyuncs.http.MethodType; import com.aliyuncs.profile.DefaultProfile; /* pom.xml <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.3</version> </dependency> */ public class SendSms { public static void main(String[] args) { DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "<accessKeyId>", "<accessSecret>"); //密钥 IAcsClient client = new DefaultAcsClient(profile); CommonRequest request = new CommonRequest(); request.setSysMethod(MethodType.POST); request.setSysDomain("dysmsapi.aliyuncs.com"); request.setSysVersion("2017-05-25"); request.setSysAction("SendSms"); request.putQueryParameter("RegionId", "cn-hangzhou"); try { //模板CODE、手机、签名等都在request中 CommonResponse response = client.getCommonResponse(request); System.out.println(response.getData()); } catch (ServerException e) { e.printStackTrace(); } catch (ClientException e) { e.printStackTrace(); } } }
发现很简单,我们就是把一些参数封装进request中,其他基本可以照抄:
@Slf4j public class SendSmsUtils { // 阿里云API密钥,注意空格 private static String accessKeyId = "LTAI4FrRvd4jiP4EHy782"; private static String accessSecret = "w7mImDkpvVorcKLL"; //模板 private static String templateCode= "SMS_202550742"; //签名 private static String signName = "ABC商城"; /** * * @param phoneNumber 接收手机号,可多个,验证码发送最好只一个手机号 * @param signName 签名名称 * @param templateCode 模板CODE * @param templateParam 模板参数,JSON字符串{code:123567} */ public static String SendMessage(String phoneNumber,String templateParam){ DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret); IAcsClient client = new DefaultAcsClient(profile); CommonRequest request = new CommonRequest(); request.setSysMethod(MethodType.POST); request.setSysDomain("dysmsapi.aliyuncs.com"); request.setSysVersion("2017-05-25"); request.setSysAction("SendSms"); request.putQueryParameter("RegionId", "cn-hangzhou"); // 接收手机号码,多个以逗号隔开 request.putQueryParameter("PhoneNumbers", phoneNumber); // 签名名称 request.putQueryParameter("SignName", signName); // 模板CODE request.putQueryParameter("TemplateCode", templateCode); // 模板缺失内容 request.putQueryParameter("TemplateParam", templateParam); try { CommonResponse response = client.getCommonResponse(request); System.out.println(response.getData()); return response.getData(); } catch (ServerException e) { e.printStackTrace(); return null; } catch (ClientException e) { e.printStackTrace(); return null; } } }
这样我们在controller中调用该方法即可发送成功:
@Autowired SmsService smsService; @ApiOperation("获取手机验证码") @GetMapping("/sms") @ApiImplicitParam(value = "手机号",name = "phone",required = true,dataType = "string",paramType = "query") public String getSMSCode(@RequestParam("phone") String phone){ //向验证码服务请求发送验证码 return smsService.sendMsg(phone); }
上面是一个简单的发送验证码的例子,验证码一般是用于登陆/注册时用到,而真实的项目,可以在接到请求时在后台生成验证码,然后将其放到redis中(设置过期时间),在用户收到验证码时则填写完发到后端,此时再去和redis中的验证码进行对比。
然而这样还是有多个问题需要考虑:
1、前端中请求验证码的接口暴露,可能被恶意刷接口
2、用户多次请求,重复请求(接口幂等性)
3、换ip/手机去刷
前端控制每60分钟发送一次,在接口调用时添加图形验证码(在提交时增加图片验证码来限制机器请求,一般图片验证码可以防止大部分的机器刷码)、单ip请求限制、限定每天每个号码获取短信验证码的次数、限制短信验证码的调用频率等
正常用户重复请求可以前端控制60s一次就可以了,也可以利用token机制,在前端和后端(redis)放同一个码,每次请求过来检验通过才给发验证码。
如果使用token机制还需要考虑另一个点,当数据要求比较严格时,如订单提交的幂等性,此时如果系统是分布式,考虑到并发高、且数据要求严格,此时则要对其token加上分布式锁,以保证只有一个进程拿到redis中的token并进行后面的操作。
当然一个接口保证幂等性除了token机制,还可以在后端维护一个重复表,每次请求来看下有没有重复的,重复的则不进行处理,
还有一些对数据库的操作本身是具有幂等性的,如查询,更新删除时不对值进行增量计算(例不要用a+=2,或-1等变量操作)
!!!!!!!!!!!!!!!!!扯太远了
(如果是订单的别忘了要考虑分布式事务的处理啊)
https://blog.csdn.net/weixin_42023666/article/details/89680342