当前位置:网站首页>Variable star user module
Variable star user module
2022-07-06 11:52:00 【mb61037a3723f67】
Catalog
- One : Get verification code :
- Two : Register login :
- 3、 ... and : Get user information :
- Four :Tocken Refresh mechanism :
- 5、 ... and : Modify the user's Avatar :
- 5.1: Seven cattle cloud head test :
- 5.2: Seven cattle cloud is encapsulated in the project :
- 5.3: Check the picture type and packaging :
- 5.4: Modify user avatar view :
- 5.5:YApi Interface management platform :
- 6.1: Deploy the front-end files to the server :
- 6.2: Solve the cross domain problem of front and back end :
One : Get verification code :
1: Custom converter , Then register the converter :
cmmon/utils/converters.py
from werkzeug.routing import BaseConverter
# 1: Custom converters inherit from BaseConverter
class MobileConverter(BaseConverter):
"""
Mobile number format
"""
# 2: rewrite regex
regex = r'1[3-9]\d{9}'
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
app/__init__.py
Medium def register_extensions in .
# Register custom converter
from utils.converters import MobileConverter
app.url_map.converters['mob'] = MobileConverter
- 1.
- 2.
- 3.
2: Use converters in views :
app/resources/user/passport.py
from flask import jsonify
from flask_restful import Resource
import random
from app import redis_cli
from utils.contants import SMS_CODE_EXPIRE
class SMSCodeResource(Resource):
"""
View of sending SMS verification code
"""
def get(self, mobile):
# 1: Get your phone number
# 2: Generate 6 Bit of SMS verification code
sms_code = "%06d" % (random.randint(0, 999999))
sms_code = 123456
# 3: Store SMS verification code in redis database
key = "app:code:{}".format(mobile)
redis_cli.setex(key, SMS_CODE_EXPIRE, sms_code)
# 4: Call a third party to send SMS verification code
print(" Sending SMS verification code succeeded : Phone number :{} SMS verification code {}".format(mobile,sms_code ))
return {"mobile": mobile, "sms_code": sms_code}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
3: test :
Two : Register login :
1: Configure routing information :
user/__init__.py
user_api.add_resource(LoginRegisterResource, '/authorizations')
- 1.
2: establish User User's model classes and relational tables :
common/models/user.py
from app import db
from datetime import datetime
class User(db.Model):
"""
Basic information of users
"""
__tablename__ = 'user_basic'
id = db.Column(db.Integer, primary_key=True, doc=' user ID')
mobile = db.Column(db.String(11), doc=' cell-phone number ')
name = db.Column(db.String(20), doc=' nickname ')
last_login = db.Column(db.DateTime, doc=' Last login time ')
introduction = db.Column(db.String(50), doc=' brief introduction ')
article_count = db.Column(db.Integer, default=0, doc=' Number of works ')
following_count = db.Column(db.Integer, default=0, doc=' Number of people concerned ')
fans_count = db.Column(db.Integer, default=0, doc=' Number of fans ')
profile_photo = db.Column(db.String(130), doc=' Head portrait ')
def to_dict(self):
""" Model to dictionary , For serialization processing """
return {
'id': self.id,
'name': self.name,
'photo': self.profile_photo,
# Be careful :redis I won't support it None type But it supports empty strings
'intro': self.introduction if self.introduction else "",
'art_count': self.article_count,
'follow_count': self.following_count,
'fans_count': self.fans_count
}
class Relation(db.Model):
"""
User relationship table
"""
__tablename__ = 'user_relation'
class RELATION:
# Cancel the attention
DELETE = 0
# Focus on
FOLLOW = 1
# Pull black
BLACKLIST = 2
id = db.Column(db.Integer, primary_key=True, doc=' Primary key ID')
user_id = db.Column(db.Integer, doc=' user ID') # fans id
author_id = db.Column(db.Integer, doc=' Target users ID') # author id
relation = db.Column(db.Integer, doc=' Relationship ')
update_time = db.Column(db.DateTime, default=datetime.now, doc=' Update time ')
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
app/__init__.py
from flask_migrate import Migrate
def register_extensions(app:Flask):
...
# 4: Perform database migration
Migrate(app, db)
# Note that the guide package is needed here
from models.user import User
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
Execute the migration command :
1: Migration command
export FLASK_APP = app.main
SET FLASK_APP = app.main(windows)
2: Migration initialization
flask db init
3: Build migration version
flask db migrate
4: Upgrade the migration version
flask db upgrade
Recover database data :
1: take sql File move to utils It's a bag .
2: Execute the command after remote login :
3: stay utils Created in jwt_utils.py:
import jwt
from flask import current_app
def generate_jwt(payload, expiry, secret=None):
"""
Generate jwt
:param payload: dict load
:param expiry: datetime The period of validity
:param secret: secret key
:return: jwt
"""
_payload = {'exp': expiry}
_payload.update(payload)
if not secret:
secret = current_app.config['JWT_SECRET']
token = jwt.encode(_payload, secret, algorithm='HS256')
return token.decode()
def verify_jwt(token, secret=None):
"""
test jwt
:param token: jwt
:param secret: secret key
:return: dict: payload
"""
if not secret:
secret = current_app.config['JWT_SECRET']
try:
payload = jwt.decode(token, secret, algorithm=['HS256'])
except jwt.PyJWTError:
payload = None
return payload
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
4: stay app/settings/config.py add JWT Configuration information :
class BaseConfig(object):
...
# JWT Configuration information
# JWT secret key
JWT_SECRET = "adadwAdmldadnawasdadwddnodam"
# 2 Hours of tocken Expiration time
LOGIN_TOCKEN_EXPIRE = 2
# 14 Refresh of days tockend The expiration time of
REFRESH_TOCKEN_EXPIRE = 14
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
5: Construct to generate two tocken Function of :
class LoginRegisterResource(Resource):
def _generator_tocken(self, user_id):
"""
Internally generated tocken Methods
:param user_id: The current user is logged in
:return:
"""
login_payload = {
"user_id": user_id,
"is_refresh": False
}
expire_2h = datetime.datetime.utcnow() + datetime.timedelta(hours=current_app.config["LOGIN_TOCKEN_EXPIRE"])
jwt_secret = current_app.config['JWT_SECRET']
login_tocken = generate_jwt(payload=login_payload, expiry=expire_2h, secret=jwt_secret)
refresh_payload = {
"user_id": user_id,
"is_refresh": True
}
expire_14d = datetime.datetime.utcnow() + datetime.timedelta(days=current_app.config["LOGIN_TOCKEN_EXPIRE"])
refresh_tocken = generate_jwt(payload=refresh_payload, expiry=expire_14d, secret=jwt_secret)
return login_tocken, refresh_tocken
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
6: Login registration logic :
Logic of login and registration interface :
1: To obtain parameters
1.1: mobile cell-phone number
1.2:code SMS verification code filled in by the user
2: Test parameters —RequestParser
3: Logical processing
3.1: According to the mobile phone number in reis Query the real verification code in the database
3.2: Delete redis Verification code in the database
3.3: Judge whether the SMS verification code sent by the user is empty , And whether it is with redis The results found in are consistent .
3.4: Query in the database according to the mobile phone number User Whether there is
3.5: Users exist – Sign in
3.6: The user doesn't exist — register
3.7: Generate login tocken And refresh tocken
4: Build response returns
# Return to login tocken And refresh tocken.
class LoginRegisterResource(Resource):
def _generator_tocken(self, user_id):
...
def post(self):
# Calibration parameters
parser = RequestParser()
parser.add_argument("mobile", required=True, location="json", type=regex(r'^1[3-9]\d{9}$'))
parser.add_argument("code", required=True, location="json", type=regex(r'^\d{6}$'))
ret = parser.parse_args()
# Get the verified mobile number and SMS verification code
mobile = ret['mobile']
code = ret['code']
# According to the mobile phone number redis The real SMS verification code of the database
key = "app:code:{}".format(mobile)
real_code = redis_cli.get(key)
# Delete redis SMS verification code in
redis_cli.delete(key)
# Judge whether the SMS verification code is empty
# Notice the creation of redis Specify response decoding when data
if real_code is None or code != real_code:
return {"message": "invalid sms code"}, 400
# Get user object
user = User.query.options(load_only(User.id)).filter(User.mobile == mobile).first()
# If the user doesn't exist , A new user
if user is None:
user = User(mobile= mobile, name=mobile, last_login=datetime.datetime.now())
db.session.add(user)
else:
# If the user exists , Modify the login time of the user
user.last_login = datetime.datetime.now()
db.session.add(user)
# Try to submit , If not, roll back .
try:
db.session.commit()
except Exception as e:
db.session.rollback()
return {"messgae": e}, 507
login_tocken, refresh_tocken = self._generator_tocken(user.id)
return {
"login_tocken": login_tocken,
"refresh_tocken": refresh_tocken
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
7: test :
3、 ... and : Get user information :
1:utils/middleware
Create a decorator to get user information , Then take the initiative to decorate .
from flask import request, current_app, g
from utils.jwt_util import verify_jwt
# Access to user information
def get_userinfo():
# 1: Get the tocken Information
# The front end is required to pass Authorialization Fields carry tocken
tocken = request.headers.get("Authorization")
# 2: Conduct tocken test , The load may be empty
# tocken error , Or expired
key = current_app.config["JWT_SECRET"]
payload = verify_jwt(tocken, key)
if payload:
# Extract user information from the load
g.user_id = payload.get("user_id")
g.is_refresh = payload.get("is_refresh", False)
else:
g.user_id = None
g.is_refresh = None
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
2: stay app/__init__.py
The decorator is actively decorated :
def register_extensions(app:Flask):
...
# 5: Add request hook
from utils.middleware import get_userinfo
app.before_request(get_userinfo)
- 1.
- 2.
- 3.
- 4.
- 5.
3: Create decorators that force users to log in :
utils/decoratores.py
from flask import g
# Force users to log in
def login_required(view_func):
def wrapper(*args, **kwargs):
user_id = g.user_id
is_refresh = g.is_refresh
if user_id is None:
return {"message": "invalid tocken"}, 401
elif user_id is not None and is_refresh:
return {"message": "refresh tocken not for login"}, 403
else:
return view_func(*args, **kwargs)
return wrapper
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
4: Chinese coding problem :
app/settings/config.py
# Configure the parent class
class BaseConfig(object):
...
# Chinese coding problem :
LOGIN_AS_ASCII = False
RESTFUL_JSON = {"ensure_ascii": False}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
5: Get user information view :
app/resource/user/passport.py
# Get current login user information
class CurrentUserResource(Resource):
method_decorators = {
"get": [login_required]
}
def get(self):
# 1: To obtain parameters
user_id = g.user_id
# 2; according to user_id Query user information
user = User.query.options(load_only(User.id,
User.name,
User.profile_photo,
User.introduction,
User.article_count,
User.following_count,
User.fans_count)).filter(User.id == user_id).first()
# 3: Convert the user object into a dictionary and return
user_dict = user.to_dict()
return user_dict
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
6: Add route :
app/resource/user/__init__.py
user_api.add_resource(CurrentUserResource, '/user')
- 1.
7: To test :
Four :Tocken Refresh mechanism :
1:app/resources/user/passport.py
class LoginRegisterResource(Resource):
def _generator_tocken(self, user_id):
...
def post(self):
...
def put(self):
# 1: obtain user_id
user_id = g.user_id
# 2: Get refresh tocken Sign a
is_refresh = g.is_refresh
# 3 Determine whether to refresh tocken
if user_id and is_refresh:
login_tocken, is_refresh_tocken = self._generator_tocken(user_id)
return {"new_tocken": login_tocken, "new_login_tocken": is_refresh_tocken}
else:
return {"message": "wrong refresh tocken"}, 403
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
2: test :
5、 ... and : Modify the user's Avatar :
5.1: Seven cattle cloud head test :
1: Seven cattle cloud test case :
from qiniu import Auth, put_file, etag, put_data
import qiniu.config
def upload_pic(data):
# 1: You need to fill in your Access Key and Secret Key
access_key = 'LSo9n249hhQP9VQPHtJkNpC-2l6zAAJUgYm0q69J'
secret_key = 'lnm0ebW2Qp3CLZberagsKPfBY2p_aDo_IV-_LP-J'
# 2: Build authentication object
q = Auth(access_key, secret_key)
# 3: Space to upload
bucket_name = 'sztopnews'
# File name saved after upload , The picture name is empty , According to the picture data , Generate a unique picture name by hashing
key = None
# 4: Generate upload Token, You can specify expiration time, etc
# pit centos The time may expire , To refresh centos Time for
token = q.upload_token(bucket_name, key, 360000000)
# 5: Upload binary file data
ret, info = put_data(token, key, data)
# 6: Judge whether the upload is successful
# if info.status_code == 200:
# return ret['key']
# else:
# # Throw an exception
# raise info.exception
print(ret)
print("**"*10)
print(info)
if __name__ == '__main__':
with open("./1.png", 'rb') as f:
upload_pic(f.read())
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
2: Test run results :
5.2: Seven cattle cloud is encapsulated in the project :
1: stay app/settings/config.py
Add the configuration information of qiniu cloud :
# Configure the parent class
class BaseConfig(object):
...
# Configuration information of qiniu cloud
QINIU_ACCESS_KEY = 'LSo9n249hhQP9VQPHtJkNpC-2l6zAAJUgYm0q69J'
QINIU_SECRET_KEY = 'lnm0ebW2Qp3CLZberagsKPfBY2p_aDo_IV-_LP-J'
QINIU_BUCKET_NAME = 'sztopnews'
QINIU_DOMAIN = 'http://qji837cfs.hn-bkt.clouddn.com/'
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
2: Create in the toolkit image_storage.py:
from qiniu import Auth, put_file, etag, put_data
from flask import current_app
import qiniu.config
def upload_pic(data):
# 1: You need to fill in your Access Key and Secret Key
access_key = current_app.config['QINIU_ACCESS_KEY']
secret_key = current_app.config['QINIU_SECRET_KEY']
# 2: Build authentication object
q = Auth(access_key, secret_key)
# 3: Space to upload
bucket_name = current_app.config['QINIU_BUCKET_NAME']
# File name saved after upload , The picture name is empty , According to the picture data , Generate a unique picture name by hashing
key = None
# 4: Generate upload Token, You can specify expiration time, etc
# pit centos The time may expire , To refresh centos Time for
token = q.upload_token(bucket_name, key, 360000000)
# 5: Upload binary file data
ret, info = put_data(token, key, data)
# 6: Judge whether the upload is successful
if info.status_code == 200:
return ret['key']
else:
# Throw an exception
raise BaseException(info.exception)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
5.3: Check the picture type and packaging :
1: First test in the test file : There are two schemes, one is to pass in the object , An incoming picture data .
import imghdr
with open("./1.png", "rb") as f:
# Scheme 1
# Check the type of file
type = imghdr.what(f)
print(type)
# Option two :
type2 = imghdr.what(None, f.read())
print(type2)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
2: Encapsulate the function of checking the image type into the tool class :
def img_type(value):
"""
Check whether it is a picture type
:param value:
:return:
"""
try:
type = imghdr.what(value)
except Exception as e:
raise ValueError(e)
if type:
return value
else:
raise ValueError("invalid image type")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
5.4: Modify user avatar view :
1:app/user/profile/py
Create a view in :
from flask_restful import Resource
from flask import g
from app import db
from models.user import User
from utils.decoratores import login_required
from flask_restful.reqparse import RequestParser
from flask import current_app
from utils.img_storage import upload_pic
from utils.parser import img_type
class UserPhotoResource(Resource):
"""
Modify the view of user avatar
"""
method_decorators = {
"patch": [login_required]
}
def patch(self):
# 1: To obtain parameters
user_id = g.user_id
# 2: Test parameters
parser = RequestParser()
parser.add_argument("photo", required=True, location="files", type=img_type)
ret = parser.parse_args()
# 3: Get the inspected image object
photo_file = ret['photo']
# 4: Convert pictures into binary data
photo_bytes = photo_file.read()
# 5: Call the tool class and upload it to qiniu cloud
try:
img_name = upload_pic(photo_bytes)
except Exception as e:
return {"message": "Third Error : {}".format(e)}, 500
# TODO : Store the picture name or store it completely URL The path ?
# The name of the stored picture is good , It is convenient to modify the domain name in the future
# 6: Splice the complete picture url Address
full_url = current_app.config["QINIU_DOMAIN"] + img_name
# 7: Query the user , Update user profile
User.query.filter(User.id == user_id).update({"profile_photo": full_url})
try:
db.session.commit()
except Exception as e:
return {"message": e}, 507
return {"photo_url": full_url}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
2: Add route user/__init__.py
user_api.add_resource(UserPhotoResource, '/user/photo')
- 1.
3: test : Both the database and the response exist .
5.5:YApi Interface management platform :
1:YApi The experience area of :
2:YApi Official documents of :
hellosean1025.github.io/yapi
6、 ... and : View front end interactions :
6.1: Deploy the front-end files to the server :
1: Decompress the front-end package locally :
2: Upload the file to the server :
3: Enter the virtual environment , Then start the front-end file :
6.2: Solve the cross domain problem of front and back end :
1: install flask_cors:
pip install flask-cors
2: To solve the cross domain :
app/__init__.py
from flask_cors import CORS
def register_extensions(app:Flask):
...
# 6: Add cross domain request
# app: Allow cross domain app object ,
# supports_credentials= True, It is carried when supporting cross domain cookie and session,tocken authentication
# methods = [], Allow cross domain requests . All are allowed by default .
CORS(app, supports_credentials=True)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
边栏推荐
猜你喜欢
Kept VRRP script, preemptive delay, VIP unicast details
保姆级出题教程
error C4996: ‘strcpy‘: This function or variable may be unsafe. Consider using strcpy_ s instead
Small L's test paper
Come and walk into the JVM
Stage 4 MySQL database
Machine learning notes week02 convolutional neural network
Word typesetting (subtotal)
MTCNN人脸检测
Linux yum安装MySQL
随机推荐
ImportError: libmysqlclient. so. 20: Cannot open shared object file: no such file or directory solution
[MRCTF2020]套娃
【presto】presto 参数配置优化
ES6 Promise 对象
Pytoch Foundation
STM32型号与Contex m对应关系
Codeforces Round #753 (Div. 3)
ES6 let and const commands
Word typesetting (subtotal)
使用LinkedHashMap实现一个LRU算法的缓存
MySQL数据库面试题
Nodejs connect mysql
MySQL START SLAVE Syntax
Redis interview questions
牛客Novice月赛40
FTP文件上传文件实现,定时扫描文件夹上传指定格式文件文件到服务器,C语言实现FTP文件上传详解及代码案例实现
[AGC009D]Uninity
Niuke novice monthly race 40
[Blue Bridge Cup 2017 preliminary] buns make up
[NPUCTF2020]ReadlezPHP