aliyun阿里云发送短信验证码和校验

第一步。前端调用发送短信验证码的接口

  @Autowired
    private ResetPasswordService resetPasswordService;

    @GetMapping("/validate-code")
    public Result validateCode(@RequestParam String phone) {
        return resetPasswordService.validateCode(phone);
    }

第二步,生成验证码并发送(自主生成验证码),反馈给前端

	@Autowired
    private IIdentifyingCodeService identifyingCodeService;
    
	public static final String USER_REGISTER_PASSWORD = "register_password";
	//要发送的短信内容
    private String templateOfRegisterStoreSms = "【***-**】%s(****验证码)。工作人员不会向您索要,请勿向任何人泄露,以免造成账户或资金损失。";
    //验证码的生成范围
    private int startInclusive = 1000;
    private int endInclusive = 9999;
    //验证码有效期
    private int expire = 60 * 1000;
    
	@Override
    public String validateCode(String phone) {
		//生成验证码
        int code = RandomUtils.nextInt(startInclusive, endInclusive);
        
        String tokenId= identifyingCodeService.sendCode(phone, USER_REGISTER_PASSWORD, templateOfRegisterStoreSms,String.valueOf(code), expire);
        return tokenId;
    }

第三步,发送验证码的service和impl


/**
 * identifying code service
 * @author author 
 * @date 2020年2月14日
 */
public interface IIdentifyingCodeService {

    /**
     * 发送认证码
     * @param target 目标,一般为手机号
     * @param type 类型,该类型由具体的使用者自定义即可,只要确保在本方法使用中的type一致即可,该字段作为tokenId的一部分
     * @param template 消息模板,的定义,默认使用 %s 来格式化字符串,即模板中包含的 %s 将被 参数 code 替换
     * @param code 认证码,请自主生成
     * @param expire 超时时间,该认证码失效的时间,单位为秒
     * @return tokenId 认证码与本tokenId一一对应
     */
    String sendCode(String target, String type, String template, String code, int expire);

    /**
     * 获取tokenId对应的code
     * @param type 参考上述定义
     * @param tokenId
     * @return code
     */
    String getCode(String type, String tokenId);

    /**
     * 清空tokenId对应的code
     * @param type 参考上述定义
     * @param tokenId }方法返回的tokenId
     * @return code
     */
    void clean(String type, String tokenId);
}


/**
 * identifying code service impl
 * @author author 
 * @date 2020年2月14日
 */
@Service
@Slf4j
public class IIdentifyingCodeServiceImpl implements IIdentifyingCodeService {

    public static final String PREFIX_SMS = "SMS";
    public static final String PREFIX_IDENTIFYING = "IDENTIFYING";
    public static final String IDENTIFYING_TYPE_OF_POLICY = "policy";

    private  String separator = ":";
    private  int keyLength = 10;
    private  int policyTime = 60 * 1000;
    @Autowired
    private RedisUtils redisUtils;

    @Override
    public String sendCode(String target, String type, String template, String code, int expire) {
        Result result = timePolicy(target, policyTime);
        if(result.getCode().equals(ResultEnum.OPRATOR_FAIL.getCode())){
            return result;
        }
        //阿里发送短信验证码
        AliSMSClient.sendSMS(target,code);
        String tokenId = generatorTokenId();
        redisUtils.setValue(generatorKey(type, tokenId), code, expire);
        return tokenId;
    }

    protected String generatorKey(String type, String tokenId) {
        String key = new StringBuffer()
                .append(PREFIX_SMS)
                .append(separator)
                .append(PREFIX_IDENTIFYING)
                .append(separator)
                .append(type)
                .append(separator)
                .append(tokenId).toString();
        return key;
    }

    protected String generatorTokenId() {
        return RandomStringUtils.randomAlphabetic(keyLength);
    }

    protected Result timePolicy(String target, int ttl) {
        Object  oTarget= redisUtils.getValue(generatorKey(IDENTIFYING_TYPE_OF_POLICY, target));
        if (Objects.nonNull(oTarget)) {
            log.debug("identifying code time policy: target [{}] is failed. ttl=[{}]", target, ttl);
            return RespUtil.error(ResultEnum.OPRATOR_FAIL.getCode(),ttl / 1000 + "秒内不能再次发送短信");
        } else {
            redisUtils.setValue(generatorKey(IDENTIFYING_TYPE_OF_POLICY, target), target, ttl);
            return  RespUtil.success(ResultEnum.OPRATOR_SUCCESS.getCode());
        }
    }

    @Override
    public String getCode(String type, String tokenId) {
        Object obj = redisUtils.getValue(generatorKey(type, tokenId));
        if(Objects.isNull(obj)){
            return "";
        }
        return (String)obj;
    }

    @Override
    public void clean(String type, String tokenId) {
        redisUtils.setValue(generatorKey(type, tokenId), null);
    }
}

第四步,ali发送短信的接口

/**
 * 静态常量类
 * @author author 
 *
 */
public class Constants {

	/** 阿里  短信发送访问域名 */
	public static final String endpoint = "dysmsapi.aliyuncs.com";
	/** 阿里  AccessKey ID */
	public static final String accessKeyId = "accessKeyId ";
	/** 阿里  AccessKey Secret */
	public static final String accessKeySecret = "accessKeySecret ";
	/** 阿里  signName */
	public static final String signName = "signName";
	/** 阿里  templateCode */
	public static final String templateCode = "templateCode ";

}
/**
 * 
 * @author author 
 *
 */
public class AliSMSClient {

	private static Logger logger = LoggerFactory.getLogger(AliSMSClient.class);

	private AliSMSClient(){
		
	}

	public static void main(String[] args) {
		sendSMS("18700000000", "3456");
	}

	/**
	 * 使用AK&SK初始化账号Client
	 * @return Client
	 * @throws Exception
	 */
	public static Client createClient() throws Exception {
		Config config = new Config()
				// 您的AccessKey ID
				.setAccessKeyId(Constants.accessKeyId)
				// 您的AccessKey Secret
				.setAccessKeySecret(Constants.accessKeySecret)
				// 访问的域名
				.setEndpoint(Constants.endpoint);

		return new Client(config);
	}

	/**
	 * 发送短信
	 * @param phone
	 * @param SignName  短信签名名称
	 * @param TemplateCode 短信模板ID
	 * @return
	 * @throws Exception
	 */
	public static String sendSMS(String phone,String templateParam) {

		if(StringUtils.isBlank(phone)) {
			throw new IllegalArgumentException("手机号不能为空");
		}

		Client client = null;
		String ret = "";
		try {
			client = createClient();
			SendSmsRequest sendSmsRequest = new SendSmsRequest()
					.setPhoneNumbers(phone)
					.setSignName(Constants.signName)
					.setTemplateCode(Constants.templateCode)
					.setTemplateParam("{'code':'" + templateParam + "'}");
			SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
			if (null != sendSmsResponse && !"".equals(sendSmsResponse)) {
				ret = parseResponse(sendSmsResponse);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new CustomException("发送短信失败!");
		}
		return ret;
	}

	/**
	 * 解析下发response
	 * @param sendSmsResponse
	 * @return
	 */
	public static String parseResponse(SendSmsResponse sendSmsResponse) {

		//"Message":"OK", 状态码的描述。
		//"RequestId":"2184201F-BFB3-446B-B1F2-C746B7BF0657", 请求ID。
		//"BizId":"197703245997295588^0", 发送回执ID,可根据该ID在接口QuerySendDetails中查询具体的发送状态。
		//"Code":"OK" 请求状态码,返回OK代表请求成功。

		SendSmsResponseBody body = sendSmsResponse.getBody();
		if("OK".equals(body.getCode())){
			return "0";
		}else {
			return "-1";
		}
	}
}

下面是验证码校验

 	@PostMapping("/reset/password")
    public Result resetPassword(@RequestBody ResetPasswordDTO dto) {
        return resetPasswordService.resetPassword(dto);
    }
	@Override
    @Transactional(rollbackFor = Exception.class)
    public Result resetPassword(ResetPasswordDTO dto) {
        Optional<String> oToken = Optional.ofNullable(identifyingCodeService.getCode(USER_REGISTER_PASSWORD,
                dto.getTokenId()));
        if (oToken.isPresent()) {
            if (oToken.get().equals(dto.getCode())) {
                //验证成功,进行操作
                
                //清除验证码
                identifyingCodeService.clean(USER_REGISTER_PASSWORD, dto.getTokenId());
                return  RespUtil.success();
            } else {
                return RespUtil.error(ResultEnum.OPRATOR_FAIL.getCode(),"短信验证码错误.");
            }
        } else {
            return RespUtil.error(ResultEnum.OPRATOR_FAIL.getCode(),"短信验证码错误.");
        }
    }
/**
 * @author author 
 * @since 2020-09-01
 */
@Data
public class ResetPasswordDTO implements Serializable {

    /**
     * 验证码
     */
    private String code;

    /**
     * 验证码id
     */
    private String tokenId;

}
上一篇:Fabric1.4超详细环境搭建 搭建不出来本博主倒立写代码


下一篇:Android判断是debug还是release模式