前言
随着社会的发展,人类的进步。现如今登录/注册系统的操作也变的越来越简单多元化。今天主要是来讲怎么使用手机号注册/登录的,本文主要针对刚学习python的同学,有任何问题都可以提出。
提前准备:
1. python3 + flask_restful 框架
2. 阿里云的sms的短信服务,需提前申请好。阿里云sms短信服务
3. redis,用于存放验证码
4. 数据库。
正文:
1. 数据库设计:
user(用户)表:
字段 | 类型 | 含义 |
id | int | 自增ID |
name | string | 用户名 |
phone | string | 电话号码 |
status | string | 状态 |
2. 项目中数据表:
models.py 文件中添加user表
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.String(255), nullable=False)
phone = db.Column(db.String(32), nullable=False)
status = db.Column(db.String(32), nullable=False)
3. redis配置:
redis_config.py 文件中添加redis配置
import redis
class RedisCache:
def __init__(self, host, password, port=6379, use_cache=True, db=0):
self.use_cache = use_cache
try:
self.session = redis.StrictRedis(host=host, port=port, password=password, db=db, socket_timeout=10,
socket_connect_timeout=5, max_connections=5)
except Exception as e:
raise e
def set_cache(self, key, value):
if not self.use_cache:
return None
self.session.set(key, value, ex=300)
def get_cache(self, key):
if not self.use_cache:
return None
res = self.session.get(key)
return res
def delete_cache(self, key):
if not self.use_cache:
return None
self.session.delete(key)
# redis中的配置为你自己项目中的配置
redis_client = RedisCache(host='your host', port=6379, password="your password", db=1)
4. 阿里云sms短信发送:
tips: 本文使用的SDK版本是 1.0 版本 ,查看链接
sms_service.py 文件中存放sms短信服务
import uuid
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
sms = {
'SMS_ACCESS_KEY_ID': 'your key id',
'SMS_ACCESS_KEY_SECRET': 'your secret',
'SMS_SIGN_NAME': 'your sign name',
'SMS_TEMPLATE_CODE': 'your template code'
}
class SendSms(object):
def __init__(self, phone: str = None, template_param=None):
"""
:param phone: 发送的手机号
:param template_param: 短信验证码或者短信模板中需要替换的变量用字典传入类似:{"code":123456}
"""
access_key_id = sms.get('SMS_ACCESS_KEY_ID', None)
access_key_secret = sms.get('SMS_ACCESS_KEY_SECRET', None)
sign_name = sms.get("SMS_SIGN_NAME", None)
template_code = sms.get('SMS_TEMPLATE_CODE', None)
if access_key_id is None:
raise ValueError("缺失短信key")
if access_key_secret is None:
raise ValueError("缺失短信secret")
if phone is None:
raise ValueError("手机号错误")
if template_param is None:
raise ValueError("短信模板参数无效")
if sign_name is None:
raise ValueError("短信签名错误")
self.acs_client = AcsClient(access_key_id, access_key_secret, 'cn-hangzhou')
self.phone = phone
self.template_param = template_param
self.sign_name = sign_name
self.template_code = template_code
def send_sms(self):
"""
发送短信
:return:
"""
sms_request = CommonRequest()
# 固定设置
sms_request.set_accept_format('json')
sms_request.set_domain('dysmsapi.aliyuncs.com')
sms_request.set_method('POST')
sms_request.set_protocol_type('https') # https | http
sms_request.set_version('2017-05-25')
sms_request.set_action_name('SendSms')
# 短信发送的号码列表,必填。
sms_request.add_query_param('PhoneNumbers', self.phone)
# 短信签名,必填。
sms_request.add_query_param('SignName', self.sign_name)
# 申请的短信模板编码,必填
sms_request.add_query_param('TemplateCode', self.template_code)
# 短信模板变量参数 类似{"code":"12345"},必填。
sms_request.add_query_param('TemplateParam', self.template_param)
# 设置业务请求流水号,必填。暂用UUID1代替
build_id = uuid.uuid1()
sms_request.add_query_param('OutId', build_id)
# 调用短信发送接口,返回json
sms_response = self.acs_client.do_action_with_exception(sms_request)
return sms_response
5. 验证手机号:
sms_service.py 文件中存放手机验证
import re
def check_phone(phone: str):
"""check phone"""
if phone:
v_phone = re.match(r'^1[3-9][0-9]{9}$', phone)
if v_phone:
phone = v_phone.group()
return phone
else:
return None
else:
return None
6. 发送验证码:
sms_send.py 文件
from flask_restful import Resource, reqparse
from redis_config import redis_client
from sms_service import check_phone, SendSms
class SMSCodeAPI(Resource):
"""send sms code for user"""
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('phone', required=True)
args = parser.parse_args()
phone = check_phone(args['phone'])
if not args['phone'] or phone is None:
return {'result': 'fail', 'data': 'phone number error'}
# if redis_client.get(args['phone']):
# return {'result': 'fail', 'data': '请勿重复请求验证码'}
code = "".join([str(random.randint(0, 9)) for _ in range(6)])
template_param = {"code": code}
# 将验证码存入redis,方便接下来的验证
redis_client.set_cache(phone, code)
# 发送验证码
sms = SendSms(phone=phone, template_param=template_param)
response = sms.send_sms()
# into json
response = json.loads(response)
return jsonify({
'result': 'success',
'data': response
})
api.add_resource(SMSCodeAPI, '/sms_code')
7. 注册/登录验证:
from sms_service import check_phone
from flask_restful import Resource, reqparse
from redis_config import redis_client
class RegisterAPI(Resource):
"""Resource for user register, phone or wechat"""
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('name', required=True)
parser.add_argument('phone', required=True)
parser.add_argument('code', required=True)
args = parser.parse_args()
user = User.query.filter_by(phone=args['phone']).first()
# check phone and code
code, phone = args['code'], args['phone']
phone = check_phone(phone)
if phone is None:
return {'result': 'fail', 'data': 'phone number error'}
# 查找phone对应的code
region_code = redis_client.get_cache(phone)
region_code = region_code.decode('utf-8')
if not region_code:
return {'result': 'fail', 'data': 'Verification code invalid'}
if region_code != code:
return {'result': 'fail', 'data': 'Verification code error'}
db.session.begin_nested()
if account:
return {'result': 'success', 'data': user.id}
else:
try:
user= Account(name=name, phone=phone, status='pending')
db.session.add(account)
db.session.commit()
# delete cache
redis_client.delete_cache(phone)
return {'result': 'success', 'data': user.id}
except Exception as e:
db.session.rollback()
logging.error(f'Register failed: {e}')
raise AccountRegisterError(f'Registration failed: {e}') from e
api.add_resource(RegisterAPI, '/regis')
小结:
flask_restful 框架和 flask 框架类似,只是在请求数据时,flask的路由以装饰器的形式放在应用功能接口上面,而flask_restful则是用 api.add_resource() 的方法,对接口和路由进行映射。
如有问题,感谢指正