Flask 使用验证码实现手机号的登录注册

前言

        随着社会的发展,人类的进步。现如今登录/注册系统的操作也变的越来越简单多元化。今天主要是来讲怎么使用手机号注册/登录的,本文主要针对刚学习python的同学,有任何问题都可以提出。

提前准备:

        1. python3 + flask_restful 框架

        2. 阿里云的sms的短信服务,需提前申请好。阿里云sms短信服务

        3. redis,用于存放验证码

        4. 数据库。

正文:

        1. 数据库设计:

                user(用户)表:

字段类型含义
idint自增ID
namestring用户名
phonestring电话号码
statusstring状态
        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() 的方法,对接口和路由进行映射。

如有问题,感谢指正

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值