Flask简单调用Redis、MySQL和生成token及token验证

项目地址:https://github.com/MasonYyp/myflask

1 安装python基础环境

# 安装flask
pip install flask

# 安装redis
pip install redis

# 安装操作MySQL的包
pip install flask-sqlalchemy
pip install pymysql
# 安装序列化包
pip install flask-marshmallow
pip install marshmallow-sqlalchemy


# 安装生成token相关的包
pip install pyjwt

# 安装生成验证码的包
pip install captcha

2 Docker安装redis和mysql

2.1 redis.conf

# redis.conf
# 可远程连接
# bind 127.0.0.1
# 解除保护模式
protected-mode no
# 数据持久化
appendonly yes
# 设置密码
requirepass 123456

2.2 创建redis容器

sudo docker run -itd \
--restart=always \
--name fl_redis \
-p 6379:6379 \
-v /home/fl_redis/redis.conf:/etc/redis/redis.conf \
-v /home/fl_redis/data:/data \
redis:6.2.2 redis-server /etc/redis/redis.conf

2.3 创建MySQL容器

# 安装MySQL,密码是123456
sudo docker run -itd \
--restart=always \
--name fl_mysql \
-p 3306:3306 \
-v /home/mysql/conf:/etc/mysql/conf.d \
-v /home/mysql/data:/var/lib/mysql \
-v /home/mysql/log:/var/log/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7

进入MySQL容器创建数据库

create database myflask default character set utf8mb4 collate utf8mb4_unicode_ci;

3 vue前端

3.1 前端页面







3.2 截图

前端截图

Flask简单调用Redis、MySQL和生成token及token验证_第1张图片

4 flask工程

4.1 工程目录

Flask简单调用Redis、MySQL和生成token及token验证_第2张图片

4.2 代码

4.2.1 main
from flask import Flask

from route.interceptor import before_interceptor
from route.operate_blueprint import OperateBlueprint
from dao.base_db.mysql_db import init_mysql_db

app = Flask(__name__)


# 设置拦截器
@app.before_request
def route_interceptor():
    return before_interceptor()


# 初始化蓝本
operate_blueprint = OperateBlueprint(app)
operate_blueprint.init_blueprint()

# 初始化MySQL
init_mysql_db(app)


# Run the app
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
4.2.2 config目录
4.2.2.1 common.py
import os


def get_root_path():
    cur_path = os.path.abspath(os.path.dirname(__file__))
    root_path, _ = os.path.split(cur_path)

    return root_path
4.2.2.2 db_conf.py

class RedisConf:
    # 配置基本参数
    pwd = "123456"
    host = "192.168.108.100"
    port = 6379


class MysqlConf:
    acc = "root"
    pwd = "123456"
    host = "192.168.108.100"
    port = 3306
    db = "myflask"


redis_conf = RedisConf()
mysql_conf = MysqlConf()
4.2.3 dao目录
4.2.3.1 base_db.mysql_db.py
from flask import Flask
from config.db_conf import mysql_conf
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow

# 添加pymysql驱动,连接MySQL数据库
import pymysql
pymysql.install_as_MySQLdb()

# 创建MySQL单实例
mysql_db = SQLAlchemy()

# 创建Schema
mysql_schema = Marshmallow()


# 初始化MySQL数据库
def init_mysql_db(app: Flask):

    # 配置MySQL数据库url
    db_url = "mysql://" + mysql_conf.acc + ":" + mysql_conf.pwd + "@" + mysql_conf.host + ":" + str(mysql_conf.port) + "/" + mysql_conf.db
    app.config["SQLALCHEMY_DATABASE_URI"] = db_url

    # 关闭sqlalchemy自动跟踪数据库
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    # 显示底层执行的SQL语句
    app.config['SQLALCHEMY_ECHO'] = True

    # 解决‘No application found. Either work inside a view function or push an application context.’
    app.app_context().push()

    # 初始化app
    mysql_db.init_app(app)

    # 初始化schema
    mysql_schema.init_app(app)


# 初始化table
def init_table():
    # 删除表
    mysql_db.drop_all()
    # 创建表
    mysql_db.create_all()
4.2.3.2 base_db.redis_db.py
import redis
from config.db_conf import redis_conf


class RedisDB:

    # 初始化redis
    def __init__(self):
        # 设置主机、端口号和密码
        redis_pool = redis.ConnectionPool(host=redis_conf.host, port=redis_conf.port, password=redis_conf.pwd, decode_responses=True)
        self.__strict_redis = redis.StrictRedis(connection_pool=redis_pool)

    # 在redis中添加键值,并设置过期时间
    def set(self, key, value, expiry):
        self.__strict_redis.set(name=key, value=value, ex=expiry)

    # 获取值
    def get(self, key):
        return self.__strict_redis.get(name=key)

    # 获取键值的剩余时间
    def ttl(self, key):
        # Time To Live
        return self.__strict_redis.ttl(name=key)


# 设置单例模式
redis_db = RedisDB()
4.2.3.3 base_db.mysql_db.model.user_model.py
from dao.base_db.mysql_db import mysql_db as db


# 创建用户表
class User(db.Model):
    # 用户
    __tablename__ = "tf_user"

    id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32), nullable=False, unique=True)
    pwd = db.Column(db.String(32), nullable=False)

    def __repr__(self):
        # 显示对象中的信息
        return "User object: name=%s" % self.name
4.2.3.4 base_db.mysql_db.schema.user_schema.py
from dao.base_db.mysql_db import mysql_schema as ma
from dao.mysql_dao.model.user_model import User

"""
# 序列化方法1
# 需要
注意flask-marshmallow的版本:
    flask-marshmallow<0.12.0
    class AuthorSchema(ma.ModelSchema)
    
    flask-marshmallow>=0.12.0 (recommended)
    class AuthorSchema(ma.SQLAlchemyAutoSchema)
"""

# 使用flask_marshmallow初始化model
class UserSchema(ma.SQLAlchemyAutoSchema):
    class Meta:
        model = User
        load_instance = True


"""

# 序列号方法2
from marshmallow import Schema, fields

# 使用marshmallow初始化model
class UserSchema(Schema):
    id = fields.Integer()
    name = fields.String()
    pwd = fields.String()

    class Meta:
        # 设置序列化字段
        fields = ["id", "name", "pwd"]
        # 转化为有序字典
        ordered = True

"""
4.2.3 route目录
4.2.3.1 interceptor.py
from flask import request
from dao.base_db.redis_db import redis_db


# 设置拦截器
def before_interceptor():
    # Pass white list
    if white_list():
        pass
    else:
        res_status = check_token()
        if res_status == 1:
            pass
        else:
            return res_status


# 设置白名单
def white_list():
    url_white_list = ["/flask/public/captcha", "/flask/public/login", "/flask/public/register", "/flask/public/initdb"]
    cur_url = request.path

    # Pass the url
    if cur_url in url_white_list:
        return True
    else:
        return False


# 设置token
def check_token():
    token = request.headers.get("token")
    if token is None:
        return "Token None"

    token_ttl = redis_db.ttl(token)

    # 验证码已经过期
    if token_ttl <= 0:
        return "Token expired"

    # 获取redis中的code
    redis_token = redis_db.get(token)

    if token != redis_token:
        return "Token error"

    return 1
4.2.3.2 operate_blueprint.py
# Configure Blueprint

from route.public_route import public_bp
from route.userinfo import userinfo_bp


class OperateBlueprint():

    # Init the app
    def __init__(self, app):
        self.__app = app
        self.__base_path = "/flask"

    # 初始化蓝本
    def init_blueprint(self):
        # Register the blueprint
        self.__app_register_blueprint(public_bp)
        self.__app_register_blueprint(userinfo_bp)

    # 在Flask中添加蓝本
    def __app_register_blueprint(self, blueprint):
        self.__app.register_blueprint(blueprint, url_prefix=self.__base_path + blueprint.name)
4.2.3.3 public_route.py
from flask import Blueprint, jsonify, request
from service.public_service import register_user, login_user, generate_captcha, create_table


public_bp = Blueprint("/public", __name__)


@public_bp.route("/captcha", methods=['POST'])
def captcha():
    captcha_dict = generate_captcha()
    return jsonify(captcha_dict)


@public_bp.route("/login", methods=['POST'])
def login():
    # 获取json数据
    data = request.get_json()
    print(data)
    res = login_user(data['name'], data['pwd'], data['code_key'], data['code'])
    return jsonify(res)


@public_bp.route("/register", methods=['POST'])
def register():
    register_user()
    return "register"


@public_bp.route("/initdb", methods=['POST'])
def init_mysql_db():
    return create_table()
4.2.3.4 userinfo.py
from flask import Blueprint
userinfo_bp = Blueprint("/userinfo", __name__)


@userinfo_bp.route("/info", methods=['POST'])
def login():
    return "Mason"
4.2.4 service目录

public_service.py

from dao.base_db.redis_db import redis_db
from dao.base_db.mysql_db import mysql_db, init_table

from dao.mysql_dao.model.user_model import User
from dao.mysql_dao.schema.user_schema import UserSchema

from util.operate_captcha import operate_captcha
from util.operate_token import operate_token


def generate_captcha():
    # 生成验证码
    code = operate_captcha.generate_code()
    # 生成图片验证码
    image_base64_str = operate_captcha.generate_captcha_base64(code)

    # 生成唯一key
    code_key = operate_captcha.generate_code_key()

    # 存入Redis
    redis_db.set(code_key, code.casefold(), 30)

    data = {
        "code_key": code_key,
        "code_img": image_base64_str
    }

    return data


def register_user():
    user = User()
    user.name = "mason"
    user.pwd = "123456"

    # 添加数据
    mysql_db.session.add(user)
    mysql_db.session.commit()


def login_user(name, pwd, code_key, code):

    code_ttl = redis_db.ttl(code_key)

    # 验证码已经过期
    if code_ttl <= 0:
        return -1

    # 获取redis中的code
    redis_code = redis_db.get(code_key)

    # 验证码过期
    if redis_code != code.casefold():
        return -2

    # 查询数据
    user = User.query.filter_by(name=name, pwd=pwd).first()

    # 序列号对象
    user_json = UserSchema().dump(user)
    print(user_json)

    # 生成token
    token = operate_token.create_token(user.id, user.name, 60)

    # 添加到redis
    redis_db.set(token, token, 60)

    return token


def create_table():
    init_table()
    return "create table"
4.2.5 util目录
4.2.5.1 operate_captcha.py
from captcha.image import ImageCaptcha
import random

import base64
import uuid


class OperateCaptcha:

    def generate_code(self, code_len=4):
        code_chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
        chars_len = len(code_chars) - 1
        code = ''
        for _ in range(code_len):
            index = random.randint(0, chars_len)
            code = code + code_chars[index]
        return code

    def generate_captcha_base64(self, code):
        # 生成验证码
        image = ImageCaptcha()

        # 生成图片BytesIO
        img_bytes_io = image.generate(code)
        # 转化为字符串
        image_base64 = base64.b64encode(img_bytes_io.read())
        image_base64_str = "data:image/png;base64," + str(image_base64, 'utf-8')
        return image_base64_str

    def generate_code_key(self):
        # 生成唯一标识
        code_key = str(uuid.uuid1())
        return code_key


operate_captcha = OperateCaptcha()

4.2.5.2 operate_token.py
import jwt
from datetime import datetime, timedelta


# 操作Token
class OperateToken:

    def __init__(self):
        self._private_key = "123456"
        pass

    # 创建token
    def create_token(self, user_id, user_name, expiry_seconds):
        # Calculate expiry time
        expiry_time = datetime.utcnow() + timedelta(seconds=expiry_seconds)

        payload = {
            'exp': expiry_time,
            'user_id': user_id,
            'username': user_name
        }

        # 加密
        encode_jwt = jwt.encode(payload, self._private_key, algorithm='HS256')
        return encode_jwt

    # 验证token
    def check_token(self, token):
        decode_jwt = "-1"
        # 解密
        try:
            decode_jwt = jwt.decode(token, self._private_key, algorithms=['HS256'])
        except jwt.PyJWTError:
            print("Token is error!")
        return decode_jwt


operate_token = OperateToken()

5 postman截图

5.1 初始化数据表
http://127.0.0.1:5000/flask/public/initdb

Flask简单调用Redis、MySQL和生成token及token验证_第3张图片

5.2 注册接口
http://127.0.0.1:5000/flask/public/register

Flask简单调用Redis、MySQL和生成token及token验证_第4张图片

5.3 调用info接口

调用权限口需要验证token

http://127.0.0.1:5000/flask/userinfo/info

Flask简单调用Redis、MySQL和生成token及token验证_第5张图片

你可能感兴趣的:(python,Vue,flask,redis,mysql)