day102:MoFang:后端完成对短信验证码的校验&基于celery完成异步短信发送&flask_jwt_extended&用户登录的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用户登录认证。
注意:
flask_jwt_extended的作者开发当前模块主要适用于flask的普通视图方法的。其认证方式主要通过装饰器来完成。而我们当前所有服务端接口都改造成了jsonrpc规范接口,所以我们在使用过程中,需要对部分源代码进行调整才能正常使用。事实上,在我们当前使用的
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接口的更多相关文章
- Yii2在Form中处理短信验证码的Validator,耦合度最低的短信验证码验证方式
短信验证码在目前大多数web应用中都会有,本文介绍一个基于Yii2 Validator方式的验证码验证方式. 在其他文章中看到的方式大多比较难做到一次封装,多次重用. 使用此方式的好处自然不用多说,V ...
- 微服务下前后端分离的统一认证授权服务,基于Spring Security OAuth2 + Spring Cloud Gateway实现单点登录
1. 整体架构 在这种结构中,网关就是一个资源服务器,它负责统一授权(鉴权).路由转发.保护下游微服务. 后端微服务应用完全不用考虑权限问题,也不需要引入spring security依赖,就正常的 ...
- **15.app后端怎么设计用户登录方案(API权限安全)
在很多app中,都需要用户的登录操作.登录,就需要用到用户名和密码.为了安全起见,暴露明文密码的次数越少越好.怎么能最大程度避免泄露用户的密码呢?在登录后,app后端怎么去验证和维持用户的登录状态呢? ...
- XYIXY.COM短网址在线生成,快速、稳定、永久有效,免费开放网址缩短API接口。
在PHP中使用API 要在PHP程序中使用API,您必须通过file_get_contents或cURL发送GET请求:两者都是可靠的方法,您可以直接复制下面的代码. <?php /**** S ...
- Android学习笔记之短信验证码的获取和读取
PS:最近很多事情都拖拖拉拉的..都什么办事效率啊!!! 还得吐槽一下移动运营商,验证码超过五次的时候,直接把我的手机号封闭.真是受够了. 学习笔记: 1.Android之如何获取短信验证码. 2.如 ...
- 四:java调接口实现发送手机短信验证码功能
1.点击获取验证码之前的样式: 2.输入正确的手机号后点击获取验证码之后的样式: 3.如果手机号已经被注册的样式: 4.如果一个手机号一天发送超过3次就提示不能发送: 二:前台的注册页面的代码:reg ...
- PHP获取短信验证码
PHP如何获取短信验证码?以下是创蓝253短信平台下的PHP接口代码案例: <?php header("Content-type:text/html; charset=UTF-8& ...
- Android Studio精彩案例(五)《JSMS短信验证码功能实现》
转载本专栏文章,请注明出处,尊重原创 .文章博客地址:道龙的博客 很多应用刚打开的时候,让我们输入手机号,通过短信验证码来登录该应用.那么,这个场景是怎么实现的呢?其实是很多开放平台提供了短信验证功能 ...
- 重构客户注册-基于ActiveMQ实现短信验证码生产者
重构目标:将bos_fore项目中的CustomerAction作为短信消息生产者,将消息发给ActiveMQ,创建一个单独的SMS项目,作为短信息的消费者,从ActiveMQ获取短信消息,调用第三方 ...
随机推荐
- 考场(NOIP/ICPC)沙雕错误锦集(大赛前必看,救命提分良药)
记住,无论什么测试,一定要先打三题暴力(至少不会被屠得太惨) 2018.10.4 1.记得算内存.(OI一年一场空,没算内存见祖宗) 2018.10.6 1.在二分许多个字符串时(二分长度),要以长度 ...
- swjtuoj2433 Magic Mirror
描述 Magic Mirror is an artificial intelligence system developed by TAL AI LAB,It can determine human ...
- graph generation model
Generative Graph Models 第八章传统的图生成方法> The previous parts of this book introduced a wide variety of ...
- Pycharm激活码无偿分享,2020年最新Pycharm永久激活码!
2020年10月7日08:04:34更新的Pycharm激活码,还热乎着呢,速用~ 如果下边的这个Pycharm激活码过期失效了的话,大家可以关注我的微信公众号:Python联盟,然后回复" ...
- 人体动作捕捉格式之BVH
BVH简介 BVH是BioVision公司推出的一种人体动作捕捉文件格式.这种文件以节点为核心元素,记录连续数帧内人体骨架的运动. BVH=? 研究一个东西的时候我比较喜欢先研究它的名字.BVH可以认 ...
- Numpy_02
# 十,使用数组进行文件输入和输出 # Numpy 可以将数据以[文本]或[二进制]的形式存入硬盘,或从硬盘载入. # 由于大部分用户更倾向于使用pandas等其他工具来载入文本或表格型数据,因此,这 ...
- 使用KepServerEx进行数据模拟
KepServerEx是一款在工业控制中比较常见的数据采集服务软件之一,提供了多种类型的驱动,具有比较广泛的适用性.很多厂商和个人都会选择用它来做OPCServer.在项目的实施或测试过程中,我们有时 ...
- drop_cache-sar
查线上问题: 1.cpu idle 为0 ,I/O高, pidstat 发现进程io 不高,那就是cache mem引起系统io高了 没有vmstat,只能使用sar工具了,使用sar -r 查看 ...
- tcp syn-synack-ack 服务端发送syn-ack
tcp_v4_send_synack()用于发送SYNACK段,在tcp_v4_conn_request()中被调用. 首先调用tcp_make_synack()构造SYNACK段,主要是构造TCP报 ...
- 开发工具之Git(一)
目录 一.什么是Git 二.Git基本原理 三.Git用户交互 一.什么是Git 答:Git是一个分布式版本控制软件.另外提一句,它的开发者就是大名鼎鼎的Linux之父Linus. 版本控制,顾名思义 ...