目录

1.用户注册

  1.后端完成对短信验证码的校验

  2.基于celery实现短信异步发送

2.用户登录

  1.jwt登录验证:flask_jwt_extended

  2.服务端提供用户登录的API接口

1.用户注册

1.后端完成对短信验证码的校验

application.apps.users.marshmallow,代码:

from marshmallow import Schema,fields,validate,validates,ValidationError
from message import ErrorMessage as Message
from .models import User,db
class MobileSchema(Schema):
... from marshmallow_sqlalchemy import SQLAlchemyAutoSchema,auto_field
from marshmallow import post_load,pre_load,validates_schema
from application import redis
class UserSchema(SQLAlchemyAutoSchema):
... @validates_schema
def validate(self,data, **kwargs):
.... '''校验短信验证码'''
# 1. 从redis中提取验证码
redis_sms_code = redis.get("sms_%s" % data["mobile"])
if redis_sms_code is None:
raise ValidationError(message=Message.sms_code_expired,field_name="sms_code")
redis_sms_code = redis_sms_code.decode() #2. 从客户端提交的数据data中提取验证码
sms_code = data["sms_code"] #3. 字符串比较,如果失败,则抛出异常,否则,直接删除验证码
if sms_code != redis_sms_code:
raise ValidationError(message=Message.sms_code_error, field_name="sms_code")
redis.delete("sms_%s" % data["mobile"]) return data

2.基于celery实现短信异步发送

1.安装celery

pip install celery==4.4.0

2.celery主程序文件:main.py

在项目根目录下创建mycelery目录,同时创建celery启动主程序文件main.py,代码:

from __future__ import absolute_import
from celery import Celery
from application import init_app # 初始化celery对象
app = Celery("flask") # 初始化flask
flask_app = init_app("application.settings.dev").app # 加载配置
app.config_from_object("mycelery.config") # 自动注册任务
app.autodiscover_tasks(["mycelery.sms"])

3.celery配置文件:config.py

配置文件,mycelery.config,代码:

# 任务队列地址
broker_url = 'redis://127.0.0.1:6379/15' # 结果队列地址
result_backend = "redis://127.0.0.1:6379/14"

4.创建任务模块:sms/tasks.py

在mycelery下创建任务模块包sms,并创建tasks.py任务模块文件,

同时,在任务执行过程中, 基于监听器和任务bind属性对失败任务进行记录和重新尝试执行. 代码:

import json
from application import redis
from flask import current_app
from ronglian_sms_sdk import SmsSDK
from mycelery.main import app,flask_app @app.task(name="send_sms",bind=True)
def send_sms(self,mobile,sms_code):
"""发送短信"""
try:
with flask_app.app_context():
sdk = SmsSDK(
current_app.config.get("SMS_ACCOUNT_ID"),
current_app.config.get("SMS_ACCOUNT_TOKEN"),
current_app.config.get("SMS_APP_ID")
)
ret = sdk.sendMessage(
current_app.config.get("SMS_TEMPLATE_ID"),
mobile,
(sms_code, current_app.config.get("SMS_EXPIRE_TIME") // 60)
)
result = json.loads(ret) if result["statusCode"] == "000000":
pipe = redis.pipeline()
pipe.multi() # 开启事务
# 保存短信记录到redis中
pipe.setex("sms_%s" % mobile, current_app.config.get("SMS_EXPIRE_TIME"), sms_code)
# 进行冷却倒计时
pipe.setex("int_%s" % mobile, current_app.config.get("SMS_INTERVAL_TIME"), "_") pipe.execute() # 提交事务
else:
current_app.log.error("短信发送失败!\r\n%s" % ret)
raise Exception
except Exception as exc:
# 重新尝试执行失败任务
print(self.request.retries) # 本次执行的次数
self.retry(exc=exc, countdown=3, max_retries=5) """基于监听器完成任务监听"""
from celery.app.task import Task
class SMSTask(Task):
def on_success(self, retval, task_id, args, kwargs):
print( '任务执行成功!')
return super().on_success(retval, task_id, args, kwargs) def on_failure(self, exc, task_id, args, kwargs, einfo):
print('任务执行失败!%s' % self.request.retries)
# 重新尝试执行失败任务,时间间隔:3秒,最大尝试次数:5次
self.retry(exc=exc, countdown=3, max_retries=5)
return super().on_failure(exc, task_id, args, kwargs, einfo) def after_return(self, status, retval, task_id, args, kwargs, einfo):
print('this is after return')
return super().after_return(status, retval, task_id, args, kwargs, einfo) def on_retry(self, exc, task_id, args, kwargs, einfo):
print('this is retry')
return super().on_retry(exc, task_id, args, kwargs, einfo)

5.flask项目调用异步任务发送短信

flask项目调用异步任务发送短信,application.apps.home.views,代码:

@jsonrpc.method(name="Home.sms")
def sms(mobile):
"""发送短信验证码"""
# 验证手机
if not re.match("^1[3-9]\d{9}$",mobile):
return {"errno": status.CODE_VALIDATE_ERROR, "errmsg": message.mobile_format_error} # 短信发送冷却时间
ret = redis.get("int_%s" % mobile)
if ret is not None:
return {"errno": status.CODE_INTERVAL_TIME, "errmsg": message.sms_interval_time} # 生成验证码
sms_code = "%06d" % random.randint(0,999999) try:
# 异步发送短信 ******
from mycelery.sms.tasks import send_sms
send_sms.delay(mobile=mobile, sms_code=sms_code)
# 返回结果
return {"errno":status.CODE_OK, "errmsg": message.sms_is_send}
except Exception as e:
return {"errno": status.CODE_SMS_ERROR, "errmsg": message.sms_send_error}

6.运行celery

在第一个终端运行celery

主程序终端下启动: celery -A mycelery.main worker -l info
调度器终端下启动: celery -A mycelery.main beat

再开一个终端,输入如下指令

python manage.py shell
>>> from mycelery.sms.tasks import send_sms
>>> send_sms.delay(mobile="13928836666",sms_code="123456")

2.用户登录

1.jwt登录验证:flask_jwt_extended

1.flask_jwt_extended简介

当前我们开发的项目属于前后端分离,而目前最适合我们使用的认证方式就是jwt token认证。

在flask中,我们可以通过flask_jwt_extended模块来快速实现jwt用户登录认证。

注意:

  1. flask_jwt_extended的作者开发当前模块主要适用于flask的普通视图方法的。其认证方式主要通过装饰器来完成。而我们当前所有服务端接口都改造成了jsonrpc规范接口,所以我们在使用过程中,需要对部分源代码进行调整才能正常使用。

  2. 事实上,在我们当前使用的flask_jsonrpc也提供了用户登陆认证功能,但是这个功能是依靠用户账户username和密码password来实现。如果我们基于当前这种方式,也可以实现jwt登陆认证,只是相对于上面的flask_jwt_extended模块而言,要补充的代码会更多,所以在此,我们放弃这块功能的使用。

2.模块安装

pip install flask-jwt-extended

官网文档:https://flask-jwt-extended.readthedocs.io/en/latest/

配置说明:https://flask-jwt-extended.readthedocs.io/en/latest/options/

3.初始化

在魔方项目中对模块进行初始化,application/__init__.py,代码:

import os,sys
# 引入flask_jwt_extended模块
from flask_jwt_extended import JWTManager # jwt认证模块实例化
jwt = JWTManager() def init_app(config_path):
"""全局初始化""" # jwt初始化
jwt.init_app(app) return manager

4.jwt相关配置

配置文件,application.settings.dev,代码:

from . import InitConfig
class Config(InitConfig):
"""项目开发环境下的配置"""
...... # jwt 相关配置
# 加密算法,默认: HS256
JWT_ALGORITHM = "HS256"
# 秘钥,默认是flask配置中的SECRET_KEY
JWT_SECRET_KEY = "y58Rsqzmts6VCBRHes1Sf2DHdGJaGqPMi6GYpBS4CKyCdi42KLSs9TQVTauZMLMw"
# token令牌有效期,单位: 秒/s,默认: datetime.timedelta(minutes=15) 或者 15 * 60
JWT_ACCESS_TOKEN_EXPIRES = 60
# refresh刷新令牌有效期,单位: 秒/s,默认:datetime.timedelta(days=30) 或者 30*24*60*60
JWT_REFRESH_TOKEN_EXPIRES = 30*24*60*60
# 设置通过哪种方式传递jwt,默认是http请求头,也可以是query_string,json,cookies
JWT_TOKEN_LOCATION = "headers"
# 当通过http请求头传递jwt时,请求头参数名称设置,默认值: Authorization
JWT_HEADER_NAME="Authorization"
# 当通过http请求头传递jwt时,令牌的前缀。
# 默认值为 "Bearer",例如:Authorization: Bearer <JWT>
JWT_HEADER_TYPE="jwt"

5.编写登录视图函数(和jwt部分相关的)

application.apps.users.views,代码:

from application import jsonrpc,db
from .marshmallow import MobileSchema,UserSchema
from marshmallow import ValidationError
from message import ErrorMessage as Message
from status import APIStatus as status
...... from flask_jwt_extended import create_access_token,create_refresh_token,jwt_required,get_jwt_identity,jwt_refresh_token_required
from flask import jsonify,json @jsonrpc.method("User.login")
def login(account,password):
"""根据用户登录信息生成token"""
# 1. todo 根据账户信息和密码获取用户 # 2. 生成jwt token
access_token = create_access_token(identity=account)
refresh_token = create_refresh_token(identity=account)
return "ok" @jsonrpc.method("User.info")
@jwt_required # 验证jwt
def info():
"""获取用户信息"""
user_data = json.loads(get_jwt_identity()) # get_jwt_identity 用于获取载荷中的数据
return "ok" @jsonrpc.method("User.refresh")
@jwt_refresh_token_required
def refresh():
"""重新获取新的认证令牌token"""
current_user = get_jwt_identity()
# 重新生成token
access_token = create_access_token(identity=current_user)
return access_token

6.修改jwt源码

装饰器jwt_required就是用于获取客户端提交的数据中的jwt的方法,这里,我们需要进行2处调整。以方便它更好的展示错误信息。

flask_jwt_extended/view_decorators.py,代码:

from jwt.exceptions import ExpiredSignatureError
from flask_jwt_extended.exceptions import InvalidHeaderError
from message import ErrorMessage as message
from status import APIStatus as status
def jwt_required(fn):

@wraps(fn)
def wrapper(*args, **kwargs):
try:
verify_jwt_in_request()
except NoAuthorizationError:
return {"errno":status.CODE_NO_AUTHORIZATION,"errmsg":message.no_authorization}
except ExpiredSignatureError:
return {"errno":status.CODE_SIGNATURE_EXPIRED,"errmsg":message.authorization_has_expired}
except InvalidHeaderError:
return {"errno":status.CODE_INVALID_AUTHORIZATION,"errmsg":message.authorization_is_invalid}
return fn(*args, **kwargs)
return wrapper

当前文件,另一个验证函数jwt_refresh_token_required,代码:

def jwt_refresh_token_required(fn):

    @wraps(fn)
def wrapper(*args, **kwargs):
try:
verify_jwt_refresh_token_in_request()
except NoAuthorizationError:
return {"errno":status.CODE_NO_AUTHORIZATION,"errmsg":message.no_authorization}
except ExpiredSignatureError:
return {"errno":status.CODE_SIGNATURE_EXPIRED,"errmsg":message.authorization_has_expired}
except InvalidHeaderError:
return {"errno":status.CODE_INVALID_AUTHORIZATION,"errmsg":message.authorization_is_invalid}
return fn(*args, **kwargs)
return wrapper

2.服务端提供用户登录的API接口

application.apps.users.views,视图实现并完成登陆接口,代码:

from flask_jwt_extended import create_access_token,create_refresh_token,jwt_required,get_jwt_identity,jwt_refresh_token_required
from flask import jsonify,json
from sqlalchemy import or_
from .models import User
from message import ErrorMessage as message
from status import APIStatus as status
@jsonrpc.method("User.login")
def login(account,password):
"""根据用户登录信息生成token"""
# 1. 根据账户信息和密码获取用户
if len(account) < 1:
return {"errno":status.CODE_NO_ACCOUNT,"errmsg":message.account_no_data}
user = User.query.filter(or_(
User.mobile==account,
User.email==account,
User.name==account
)).first() # 检测用户是否存在
if user is None:
return {"errno": status.CODE_NO_USER,"errmsg":message.user_not_exists} # 验证密码
if not user.check_password(password):
return {"errno": status.CODE_PASSWORD_ERROR, "errmsg":message.password_error} # 2. 生成jwt token
access_token = create_access_token(identity=user.id)
refresh_token = create_refresh_token(identity=user.id) return {"access_token": access_token,"refresh_token":refresh_token} @jsonrpc.method("User.info")
@jwt_required # 验证jwt
def info():
"""获取用户信息"""
user_data = json.loads(get_jwt_identity()) # get_jwt_identity 用于获取载荷中的数据
print(user_data)
return "ok" @jsonrpc.method("User.refresh")
@jwt_refresh_token_required
def refresh():
"""重新获取新的认证令牌token"""
current_user = get_jwt_identity()
# 重新生成token
access_token = create_access_token(identity=current_user)
return access_token

day102:MoFang:后端完成对短信验证码的校验&基于celery完成异步短信发送&flask_jwt_extended&用户登录的API接口的更多相关文章

  1. Yii2在Form中处理短信验证码的Validator,耦合度最低的短信验证码验证方式

    短信验证码在目前大多数web应用中都会有,本文介绍一个基于Yii2 Validator方式的验证码验证方式. 在其他文章中看到的方式大多比较难做到一次封装,多次重用. 使用此方式的好处自然不用多说,V ...

  2. 微服务下前后端分离的统一认证授权服务,基于Spring Security OAuth2 + Spring Cloud Gateway实现单点登录

    1.  整体架构 在这种结构中,网关就是一个资源服务器,它负责统一授权(鉴权).路由转发.保护下游微服务. 后端微服务应用完全不用考虑权限问题,也不需要引入spring security依赖,就正常的 ...

  3. **15.app后端怎么设计用户登录方案(API权限安全)

    在很多app中,都需要用户的登录操作.登录,就需要用到用户名和密码.为了安全起见,暴露明文密码的次数越少越好.怎么能最大程度避免泄露用户的密码呢?在登录后,app后端怎么去验证和维持用户的登录状态呢? ...

  4. XYIXY.COM短网址在线生成,快速、稳定、永久有效,免费开放网址缩短API接口。

    在PHP中使用API 要在PHP程序中使用API,您必须通过file_get_contents或cURL发送GET请求:两者都是可靠的方法,您可以直接复制下面的代码. <?php /**** S ...

  5. Android学习笔记之短信验证码的获取和读取

    PS:最近很多事情都拖拖拉拉的..都什么办事效率啊!!! 还得吐槽一下移动运营商,验证码超过五次的时候,直接把我的手机号封闭.真是受够了. 学习笔记: 1.Android之如何获取短信验证码. 2.如 ...

  6. 四:java调接口实现发送手机短信验证码功能

    1.点击获取验证码之前的样式: 2.输入正确的手机号后点击获取验证码之后的样式: 3.如果手机号已经被注册的样式: 4.如果一个手机号一天发送超过3次就提示不能发送: 二:前台的注册页面的代码:reg ...

  7. PHP获取短信验证码

    PHP如何获取短信验证码?以下是创蓝253短信平台下的PHP接口代码案例:   <?php header("Content-type:text/html; charset=UTF-8& ...

  8. Android Studio精彩案例(五)《JSMS短信验证码功能实现》

    转载本专栏文章,请注明出处,尊重原创 .文章博客地址:道龙的博客 很多应用刚打开的时候,让我们输入手机号,通过短信验证码来登录该应用.那么,这个场景是怎么实现的呢?其实是很多开放平台提供了短信验证功能 ...

  9. 重构客户注册-基于ActiveMQ实现短信验证码生产者

    重构目标:将bos_fore项目中的CustomerAction作为短信消息生产者,将消息发给ActiveMQ,创建一个单独的SMS项目,作为短信息的消费者,从ActiveMQ获取短信消息,调用第三方 ...

随机推荐

  1. 考场(NOIP/ICPC)沙雕错误锦集(大赛前必看,救命提分良药)

    记住,无论什么测试,一定要先打三题暴力(至少不会被屠得太惨) 2018.10.4 1.记得算内存.(OI一年一场空,没算内存见祖宗) 2018.10.6 1.在二分许多个字符串时(二分长度),要以长度 ...

  2. swjtuoj2433 Magic Mirror

    描述 Magic Mirror is an artificial intelligence system developed by TAL AI LAB,It can determine human ...

  3. graph generation model

    Generative Graph Models 第八章传统的图生成方法> The previous parts of this book introduced a wide variety of ...

  4. Pycharm激活码无偿分享,2020年最新Pycharm永久激活码!

    2020年10月7日08:04:34更新的Pycharm激活码,还热乎着呢,速用~ 如果下边的这个Pycharm激活码过期失效了的话,大家可以关注我的微信公众号:Python联盟,然后回复" ...

  5. 人体动作捕捉格式之BVH

    BVH简介 BVH是BioVision公司推出的一种人体动作捕捉文件格式.这种文件以节点为核心元素,记录连续数帧内人体骨架的运动. BVH=? 研究一个东西的时候我比较喜欢先研究它的名字.BVH可以认 ...

  6. Numpy_02

    # 十,使用数组进行文件输入和输出 # Numpy 可以将数据以[文本]或[二进制]的形式存入硬盘,或从硬盘载入. # 由于大部分用户更倾向于使用pandas等其他工具来载入文本或表格型数据,因此,这 ...

  7. 使用KepServerEx进行数据模拟

    KepServerEx是一款在工业控制中比较常见的数据采集服务软件之一,提供了多种类型的驱动,具有比较广泛的适用性.很多厂商和个人都会选择用它来做OPCServer.在项目的实施或测试过程中,我们有时 ...

  8. drop_cache-sar

    查线上问题: 1.cpu  idle 为0 ,I/O高, pidstat 发现进程io 不高,那就是cache mem引起系统io高了 没有vmstat,只能使用sar工具了,使用sar -r  查看 ...

  9. tcp syn-synack-ack 服务端发送syn-ack

    tcp_v4_send_synack()用于发送SYNACK段,在tcp_v4_conn_request()中被调用. 首先调用tcp_make_synack()构造SYNACK段,主要是构造TCP报 ...

  10. 开发工具之Git(一)

    目录 一.什么是Git 二.Git基本原理 三.Git用户交互 一.什么是Git 答:Git是一个分布式版本控制软件.另外提一句,它的开发者就是大名鼎鼎的Linux之父Linus. 版本控制,顾名思义 ...