当前位置:网站首页>Variable star user module

Variable star user module

2022-07-06 11:52:00 mb61037a3723f67



Catalog



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 :

 All change star --- User module _flask

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 :

 All change star --- User module _flask_02

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 :

 All change star --- User module _redis_03

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 :

 All change star --- User module _flask_04

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 :

 All change star --- User module _flask_05

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 :

 All change star --- User module _flask_06

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 .

 All change star --- User module _redis_07

 All change star --- User module _redis_08

5.5:YApi Interface management platform :

1:YApi The experience area of :


 ​https://yapi.baidu.com​


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 :

 All change star --- User module _redis_09

3: Enter the virtual environment , Then start the front-end file :

 All change star --- User module _ Upload _10

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.



原网站

版权声明
本文为[mb61037a3723f67]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202131611250039.html