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

本文详细介绍了后端如何实现短信验证码的发送、生成、存储和验证功能。通过前端调用接口触发,后端生成随机验证码,利用阿里云短信服务发送,并在Redis中存储以供后续验证码校验。整个流程包括前端请求、生成验证码、发送短信以及验证码校验四个步骤,确保了用户注册或密码重置过程的安全性。
摘要由CSDN通过智能技术生成

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

  @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";
		}
	}
}

pom文件

		<dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>dysmsapi20170525</artifactId>
            <version>2.0.1</version>
        </dependency>

下面是验证码校验

 	@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;

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的阿里云短信验证码前后端交互注册页面的应用代码示例: 前端页面代码: ```html <!DOCTYPE html> <html> <head> <title>阿里云短信验证码前后端交互注册页面</title> <script src="//cdn.bootcss.com/jquery/3.3.1/jquery.js"></script> </head> <body> <h1>阿里云短信验证码前后端交互注册页面</h1> <form> <label for="phone">手机号码:</label> <input type="text" id="phone" name="phone" required> <br> <label for="code">验证码:</label> <input type="text" id="code" name="code" required> <input type="button" id="send-code" value="发送验证码"> <br> <input type="submit" value="注册"> </form> <script type="text/javascript"> $(document).ready(function() { // 发送验证码按钮点击事件 $('#send-code').click(function() { var phone = $('#phone').val(); // 发送验证码请求 $.post('/send-code', {'phone': phone}, function(data) { if (data.code == 200) { alert('验证码发送成功,请注意查收!'); } else { alert('验证码发送失败,请重试或联系管理员!'); } }, 'json'); }); }); </script> </body> </html> ``` 后端代码: ```python import random import json from flask import Flask, request app = Flask(__name__) # 存储手机号码和验证码的字典 phone_code_dict = {} # 发送验证码接口 @app.route('/send-code', methods=['POST']) def send_code(): phone = request.form['phone'] # 生成 6 位随机验证码 code = ''.join(random.sample('0123456789', 6)) # 存储手机号码和验证码 phone_code_dict[phone] = code # TODO: 调用阿里云短信服务发送验证码 # 模拟发送验证码 print('发送验证码:', phone, code) return json.dumps({'code': 200, 'msg': '验证码发送成功'}) # 注册接口 @app.route('/register', methods=['POST']) def register(): phone = request.form['phone'] code = request.form['code'] if phone not in phone_code_dict: # 手机号码未发送过验证码 return json.dumps({'code': 400, 'msg': '手机号码未发送过验证码'}) if code != phone_code_dict[phone]: # 验证码不匹配 return json.dumps({'code': 400, 'msg': '验证码不匹配'}) # TODO: 执行注册逻辑 return json.dumps({'code': 200, 'msg': '注册成功'}) ``` 该示例使用 Flask 框架实现了一个简单的后端应用,包含发送验证码和注册两个接口。其中,发送验证码接口生成 6 位随机验证码并存储到字典中,模拟调用阿里云短信服务发送验证码;注册接口从请求参数中获取手机号码和验证码,校验验证码是否匹配,如果匹配则执行注册逻辑。前端页面通过 jQuery 实现了发送验证码按钮的点击事件,点击后向后端发送请求并根据响应结果弹出提示框。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值