接着上一篇,这次说手机验证码 ,使用的阿里短信支持
1、使用场景
移动端或者网站登录,注册等等手机号验证
2、步骤
2.1、前端,填写手机号,点击发送验证码
2.2、服务器,生成验证码,调用阿里接口发送验证码,保存验证码和对应key(一般为手机号)
2.3、用户收到短信,前端输入,提交表单
2.4、服务器接收请求,校验验证码,处理业务
注:阿里短信申请过程不再此处描述
配置文件设置:
alisms: accessKeyId: ******************* accessSecret: ********************** signName: ***** templateCode: ***** //如果只有一个模板可以使用
#根据业务不同我将模板参数配置到枚举类中,便于动态使用 # idCardCode: SMS_18*****74 #身份验证验证码 # LoginCode: SMS_18*****73 #登录确认验证码 # LoginExceptionCode: SMS_187****72 #登录异常验证码 # userRegisterCode: SMS_187****71 #用户注册验证码 # updatePwdCode: SMS_187****70 #修改密码验证码 # changeInfoCode: SMS_18*****69 #信息变更验证码
工具类:
package com.*****.util.sendMessage; 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; import com.google.gson.Gson; import com.*******.vo.SendCodeDO; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * @Description: 短信发送工具 * @Author: Joe * @CreateDate: 2020/3/21 15:49 */ @Configuration public class SendSmsUtil { //阿里云keyID @Value("${alisms.accessKeyId}") private String accessKeyId; //阿里云秘钥,与keyID搭配 @Value("${alisms.accessSecret}") private String accessSecret; //短信签名-可在短信控制台中找到 @Value("${alisms.signName}") private String signName; // 短信模板-可在短信控制台中找到 @Value("${alisms.templateCode}") private String templateCode; //短信验证码集合——用于控制有效时间 private static Map<String, SendCodeDO> codeMap=new ConcurrentHashMap<>(); //过期时间 private static final long expiredTime=1000*10*60; /************************请求示例******************************************** http://dysmsapi.aliyuncs.com/?Signature=NAxwl1W9ROkidJfGeZrsKUXw%2BQ4%3D &AccessKeyId=testId &Action=SendSms &Format=XML &RegionId=cn-hangzhou &SignatureMethod=HMAC-SHA1 &SignatureNonce=313ef0fb-0393-464f-a6e2-59d9ca2585b1 &SignatureVersion=1.0 &Timestamp=2019-01-08T08%3A18%3A18Z &Version=2017-05-25 ***************************************************************************/ /** * PhoneNumbers 手机号 * TemplateParam 验证码 * templateCode2 短信模板——根据不同模板发送不同消息 例如:1、你当前正在登陆,验证码为111111 2、你正在进行身份验证,验证码为111111 */ public String aliSendSms(String PhoneNumbers,String TemplateParam,String templateCode2){ String result = ""; // regionId:API支持的RegionID,如短信API的值为:cn-hangzhou; // AccessKey ID和AccessKey Secret是您访问阿里云API的密钥,具有该账户完全的权限. DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret); IAcsClient client = new DefaultAcsClient(profile); CommonRequest request = new CommonRequest(); //请求格式 request.setMethod(MethodType.POST); //请求地址 request.setDomain("dysmsapi.aliyuncs.com"); //API 的版本号,格式为 YYYY-MM-DD。取值范围:2017-05-25。 request.setVersion("2017-05-25"); //不可改:阿里云系统规定参数——取值:SendSms。 request.setAction("SendSms"); request.putQueryParameter("RegionId", "cn-hangzhou");//不需要修改 //必填:待发送手机号 request.putQueryParameter("PhoneNumbers", PhoneNumbers); // 必填:短信签名-可在短信控制台中找到必须是已添加、并通过审核的短信签名 request.putQueryParameter("SignName", signName); // 必填:短信模板-可在短信控制台中找到;必须是已添加、并通过审核的短信签名;且发送国际/港澳台消息时,请使用国际/港澳台短信模版。 request.putQueryParameter("TemplateCode", templateCode2); //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 request.putQueryParameter("TemplateParam", TemplateParam); try { //发送请求并获取请求结果 CommonResponse response = client.getCommonResponse(request); System.out.println(response.getData()); String infojson = response.getData(); //将结果转换为Map Gson gson2 = new Gson(); Map map = gson2.fromJson(infojson, Map.class); String codes = map.get("Message").toString(); System.out.println("codes="+codes); //判断返回值是否成功 if(codes.equals("OK")){ result="ok"; }else { result="not_ok"; } } catch (ServerException e) { //异常信息打印 e.printStackTrace(); } catch (ClientException e) { //异常信息打印 e.printStackTrace(); } //输出结果 System.out.println("result="+result); return result; } /** *将验证码保存至集合中 * @param key * @param code *@return () *@throws *@author yutf *@date 2020/5/23 * */ public void saveMap(String key,String code){ //保存验证码 SendCodeDO sendCodeDO=new SendCodeDO(); sendCodeDO.setCode(code); sendCodeDO.setSendTime(System.currentTimeMillis()); codeMap.put(key,sendCodeDO); } /** *阿里云短信发送——单个模板发送信息 * @param PhoneNumbers * @param TemplateParam *@return ({@link java.lang.String}) *@throws *@author yutf *@date 2020/5/23 * */ public String aliSendSms(String PhoneNumbers,String TemplateParam){ String result = ""; DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret); IAcsClient client = new DefaultAcsClient(profile); CommonRequest request = new CommonRequest(); request.setMethod(MethodType.POST); request.setDomain("dysmsapi.aliyuncs.com"); request.setVersion("2017-05-25"); request.setAction("SendSms"); request.putQueryParameter("RegionId", "cn-hangzhou"); request.putQueryParameter("PhoneNumbers", PhoneNumbers); request.putQueryParameter("SignName", signName); request.putQueryParameter("TemplateCode", templateCode); request.putQueryParameter("TemplateParam", TemplateParam); try { CommonResponse response = client.getCommonResponse(request); System.out.println(response.getData()); String infojson = response.getData(); Gson gson2 = new Gson(); Map map = gson2.fromJson(infojson, Map.class); String codes = map.get("Message").toString(); System.out.println("codes="+codes); if(codes.equals("OK")){ result="ok"; }else { result="not_ok"; } } catch (ServerException e) { e.printStackTrace(); } catch (ClientException e) { e.printStackTrace(); } System.out.println("result="+result); return result; } /** *校验验证码 * @param key * @param code *@return ({@link boolean}) *@throws *@author yutf *@date 2020/5/23 * */ public static boolean verifyCode( String key,String code){ //清理集合中过期的验证码 cleanEmailMap(); //如果集合中包含验证码则返回true否则返回false if(codeMap.containsKey(key)){ if(codeMap.get(key).getCode().equals(code)){ return true; } } return false; } /** * 清理集合中过期的验证码 *@return () *@throws *@author yutf *@date 2020/5/23 * */ public static void cleanEmailMap() { //如果集合不为空 if(!codeMap.isEmpty()){ //循环集合——如果当前时间减去验证码创建时间大于过期时间则清除验证码 for (Map.Entry<String, SendCodeDO> stringSendEmailDOEntry : codeMap.entrySet()) { if(((System.currentTimeMillis()-stringSendEmailDOEntry.getValue().getSendTime())>expiredTime)){ codeMap.remove(stringSendEmailDOEntry.getKey()); } } } } }
应用到的实体
package com.*****.vo; import lombok.Data; /** * 功能: * 〈验证码实体〉 * * @author ytf * @create 2020/4/22 * @since 1.0.0 */ @Data public class SendCodeDO { private String code; private long sendTime; }
使用示例
/** * 发送验证码——身份验证验证码 * @param PhoneNumbers 手机号 * @return */ @ApiOperation(value = "发送验证码——登录;参数——手机号") @GetMapping(value = "/sendSms") public ResultVo loginCodeSendSms(String PhoneNumbers){ if(StringUtils.isBlank(PhoneNumbers)){ return ResultVOUtils.error(ResultEnum.PARAM_VERIFY_FAIL,"手机号不能为空"); } //随机生成验证码 String numeral = String.valueOf(new Random().nextInt(899999) + 100000); SmsData smsData = new SmsData(numeral);
//发送验证码 Gson gson = new Gson(); String code = gson.toJson(smsData); String information = sendSmsUtil.aliSendSms(PhoneNumbers, code, TypeConstant.ShortMessageType.loginCode.getCode()); String key=PhoneNumbers+TypeConstant.ShortMessageType.loginCode.getCode()+TypeConstant.PlatformType.app.getCode();
//保存 sendSmsUtil.saveMap(key,numeral); if(information.equals("ok")){ return ResultVOUtils.success("短信已发送,请注意查收"); } return ResultVOUtils.error(ResultEnum.NOT_NETWORK,"短信发送失败,请联系管理员"); } /** * 验证 * @param PhoneNumbers * @param code * @return */ @ApiOperation(value = "登录:参数——手机号,验证码") @RequestMapping(value = "/loginCode/verifySms",method = RequestMethod.POST) public ResultVo<B01UserAppVO> loginCodeVerifySms(String PhoneNumbers, String code){ if(StringUtils.isBlank(PhoneNumbers)){ throw new JsonException(ResultEnum.PARAM_VERIFY_FAIL,"手机号不能为空"); } if(StringUtils.isBlank(code)){ throw new JsonException(ResultEnum.PARAM_VERIFY_FAIL,"验证码不能为空"); } String key=PhoneNumbers+TypeConstant.ShortMessageType.loginCode.getCode()+TypeConstant.PlatformType.app.getCode();
//校验 boolean b = sendSmsUtil.verifyCode(key, code); if(b){ // 处理业务逻辑...... } return ResultVOUtils.error(ResultEnum.PARAM_VERIFY_FAIL,"验证码错误"); }
枚举类代码
/** * 功能描述: <br> * 〈短息你验证码类型编码〉 # idCardCode: SMS_187*****74 #身份验证验证码 # LoginCode: SMS_187*****73 #登录确认验证码 # LoginExceptionCode: SMS_18****672 #登录异常验证码 # userRegisterCode: SMS_1*****671 #用户注册验证码 # updatePwdCode: SMS_18*****670 #修改密码验证码 # changeInfoCode: SMS_187*****69 #信息变更验证码 * @return: * @since: 1.0.0 * @Author: * @Date: */ public enum ShortMessageType { idCardCode("SMS_18*****674","身份验证验证码"), loginCode("SMS_187****73","登录确认验证码"), loginExceptionCode("SMS_1875****2","登录异常验证码"), userRegisterCode("SMS_18******671","用户注册验证码"), updatePwdCode("SMS_187******70","修改密码验证码"), changeInfoCode("SMS_187*****69","信息变更验证码"); private String code; private String msg; private ShortMessageType(String code, String msg){ this.code =code; this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }