##Flask 学习小组
> 我选择使用国内的移动应用一站式云服务LeanCloud来实现短信验证功能。LeanCloud 提供了数据存储、实时消息、统计分析以及多种扩展组件,全面涵盖移动应用开发的需求,支持 iOS、Android、Web 等多平台。它帮助开发者摆脱后端开发负担以专注于产品创新,缩短开发周期、节省开发投入。所以使用 LeanCloud 来实现我的短信验证功能,简化了我的开发流程、让产品可以快速上线,提高效率。
### **功能实现流程:**
![](https://box.kancloud.cn/54ccd9d331f6aac84b4e3699763e8546_930x399.png)
1. 客户端发送请求给LeanCloud服务器,并在请求中包含该客户端的手机号码
1. LeanCloud服务器收到请求,生成相应验证码后,将该手机号码的短信内容发送给运营商服务器
1. 运营商收到请求后,转发带有验证码的短信到该手机号
1. 客户端收到短信验证码后,向LeanCloud发送验证码。
1. 此时,LeanCloud服务器检查发送出的验证码和收到的验证码是否一致。
### **REST API**
> REST是Roy Thomas Fielding在他2000年的博士论文中提出的。他是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一。REST的全称为Resource Representational State Transfer(资源在网络中以某种表现形式进行状态转移),REST描述的是在网络中client和server的一种交互形式。早期的网页是前端与后端融合在一起的,比如PHP和JSP。但这不能满足团队的高效开发,也不能适应各种Client层的需求。REST可以通过统一的接口为Web、iOS和Android提供服务,对于我的网页来说REST API 进行短信验证便捷的同时也具有一定的可扩展性。
REST API 可以让任何支持发送 HTTP 请求的设备与 LeanCloud 进行交互。使用 LeanCloud 的短信服务 REST API 可以完成很多事情,比如:
* 给指定手机号码发送短信验证码
* 验证手机号和短信验证码是否匹配
* 使用手机号和验证码进行登录
* 通过合法的手机号和验证码来重置账户密码
* 进行重要操作(例如支付)的验证确认等
### **短信验证API:**
**URL HTTP 功能**
/1.1/requestSmsCode POST 请求发送短信验证码
/1.1/verifySmsCode/(code) POST 验证短信验证码
**requestSmsCode接口:**
给某个手机号码发送验证短信:(参考官方文档)
![](https://box.kancloud.cn/7e869212f17f4690ebfe0bf6766e0ac9_1311x375.png)
概括为如下表格形式:
URL https://api.leancloud.cn/1.1/requestSmsCode
请求方式: POST
headers内容: X-LC-Id,X-LC-Key,Content-Type
data: JSON格式
其中data的内容为:
| 参数 | 约束 | 描述 |
| --- | --- | --- |
| mobilePhoneNumber | 必填 | 目标手机号码 |
| ttl | | 验证码有效时间,单位分钟(默认为 10 分钟) |
| name | | 应用名字,默认为 LeanCloud 控制台填写的应用名 |
| op | | 操作类型 |
**verifySmsCode 接口**
通过下面的 API 可以验证收到的 6 位数字验证码是否正确:(参考官方文档)
![](https://box.kancloud.cn/1766f1db219d6745f0e7a239079f58c4_1289x392.png)
概括为如下表格形式:
URL https://api.leancloud.cn/1.1/verifySmsCode/6位数字验证码?mobilePhoneNumber=186xxxxxxxx
请求方式 POST
headers内容 X-LC-Id,X-LC-Key,Content-Type
data 无
**1.注册并创建应用**
![](https://box.kancloud.cn/e843ad25ddfc77a98dc496d075283573_608x450.png)
每一个应用对应唯一的 App ID 和 App Key
![](https://box.kancloud.cn/01733127af74bc175906ddb4aec96582_579x278.png)
**2.开启短信验证码服务**
![](https://box.kancloud.cn/277525787cbf4038a2a6f3818a0a014f_869x496.png)
**3.后端代码实现**
> 后端服务器需要实现的内容是根据浏览器的GET或POST请求做出响应。对于短信验证来说后端只需要实现两个功能。
* 获取表单中电话号码,发送 POST 请求给requestSmsCode API,请求给指定电话号码发送验证短信。
* 获取表单中电话号码与验证码发送给requestSmsCode API进行验证。
~~~
sms.py :
import json
import requests
headers = {
"X-LC-Id": "1ltrHhRDe77M7FExy1RwqO78-gzGzoHsz",
"X-LC-Key": "A8gaYdOtGXRukMKTmcigwogE",
"Content-Type": "application/json",
}
REQUEST_SMS_CODE_URL= 'https://api.leancloud.cn/1.1/requestSmsCode'
VERIFY_SMS_CODE_URL = 'https://api.leancloud.cn/1.1/verifySmsCode/'
def send_message(phone):
data = {
"mobilePhoneNumber": phone,
}
r = requests.post(REQUEST_SMS_CODE_URL, data=json.dumps(data), headers=headers)
if r.status_code == 200:
return True
else:
return False
def verify(phone, code):
target_url = VERIFY_SMS_CODE_URL + "%s?mobilePhoneNumber=%s" % (code, phone)
r = requests.post(target_url, headers=headers)
if r.status_code == 200:
return True
else:
return False
~~~
**sms.py中包含两个主要函数:**
1. send_message(phone):
给指定电话号码发送验证码短信,data中包含了JSON格式的手机号码,发送POST请求给requestSmsCode API,当HTTP状态码为200时代表发送成功,函数返回True,否则返回False。
1. verify(phone,code):
请求校验验证码与手机号,发送POST请求给verifySmsCode API,当HTTP状态码为200时代表发送成功,函数返回True,否则返回False。
~~~
views.py:
@main.route('/signup', methods=('GET', 'POST'))
def signup():
if session['user_num']:
flash('You are already signed up')
return redirect(url_for('main.index'))
form = SignupForm()
if request.method == 'GET':
phone_number = request.args.get('mobile_phone_number')
if phone_number is not None:
if sms.send_message(phone_number):
return render_template('signup.html', form=form)
else:
flash('Failed to get verification code!')
elif request.method == 'POST':
if form.validate_on_submit():
user_num = User.query.filter_by(stu_num=form.stu_num.data).first()
if user_num is None:
phone_number = form.phone_number.data
code = form.code.data
if code == '':
flash('Please enter the verification code!')
elif sms.verify(phone_number, code):
name = form.name.data
stu_num = form.stu_num.data
password = form.password.data
user = User(name,stu_num,phone_number,password)
db.session.add(user)
db.session.commit()
session['user_num'] = stu_num
session['user_name'] = name
flash("Success to sign up!")
return redirect(url_for('main.index'))
else:
flash('Verification code error, please enter again')
return render_template('signup.html', form=form)
else:
flash("The student number has been registered!", 'error')
return render_template('signup.html', form=form)
else:
flash("Please enter the correct information.")
return render_template('signup.html', form=form)
return render_template('signup.html', form=form)
~~~
注:view.py已经导入了sms.py中的函数
在视图函数中,我们先验证用户是否已经注册,如果已经注册不能再次进行注册,将返回到主页。创建用户表单并判断手机号码一栏是否输入为空,非空则判断sms.send_message(phone_number)是否为真,为真则表示已经发送验证码,即可进入下一阶段。之后判断表单是否填写完整,如有已注册用户将以flash的形式提示,否则进行验证码判断,当sms.verify(phone_number, code)为真时代表验证码输入正确,则将用户输入信息存入数据库。
~~~
sign.html:
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}注册{% endblock %}
{% block head %}
{{ super() }}
<meta charset="UTF-8">
<script type="text/javascript">
var cur_count;
var count = 60;
var InterValObj;
var phone_number;
function send_message()
{
phone_number = document.getElementById("phone_number").value
if(phone_number)
{
cur_count = count;
document.getElementById("getCode").setAttribute("disabled", "true");
document.getElementById("getCode").value = "waiting for "+cur_count+"s";
InterValObj = window.setInterval(set_remain_time, 1000);
loadXMLDoc();
}
else
{
alert('Please input phone number!')
}
}
function set_remain_time()
{
if (cur_count == 0)
{
window.clearInterval(InterValObj);
document.getElementById("getCode").removeAttribute("disabled");
document.getElementById("getCode").value = "Get New Code";
}else
{
cur_count--;
document.getElementById("getCode").value = "waiting for "+cur_count+"s";
}
}
function loadXMLDoc()
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "signup?mobile_phone_number=" + phone_number, true);
xmlhttp.send();
}
</script>
{% endblock %}
{% block page_content %}
<div class="page-header">
<h2>注册</h2>
<form>
表单内容,与短信内容无关,暂时隐藏
</form>
</div>
{% endblock %}
~~~
前端的实现中使用到了简单的Ajax异步处理和JavaScript的倒计时,AJAX= Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。AJAX不是新的编程语言,而是一种使用现有标准的新方法。AJAX 是在不重新加载整个页面的情况下与服务器交换数据并更新部分网页的技术。通过使用JavaScript可以让页面动态显示再次发送验证码的剩余时间,时间到后可以点击再次发送验证码,而这一过程并不需要重新加载页面。
* * * * *
本人微信:sunyutong0725
欢迎交流