【自学开发之旅】Flask-前后端联调-异常标准化返回

注册联调:

前端修改:
1.修改请求向后端的url地址
文件:env.development修改成VITE_API_TARGET_URL= http://127.0.0.1:9000/v1

登录:token验证

校验forms/user.py

from werkzeug.security import check_password_hash


# 登录校验
class Loginform(Form):
    username = StringField(validators=[DataRequired()])
    password = StringField(validators=[DataRequired(), Regexp(r'\w{6,18}', message="密码不符合要求")])

    def validate(self):
        super().validate()
        if self.errors:
            return False
        user = User.query.filter_by(username = self.username.data).first()
        if user and check_password_hash(user.password, self.password.data):
            return user
        else:
            raise ValidationError("验证失败!")

router/user/user.py

from libs.auth import create_token

# 登录视图
class LoginView(Resource):
    def post(self):
        data = request.json
        form = LoginForm(data = data)
        user = form.validate()
        if user:
            return generate_response(msg="login success!", code=0)
        else:
            return generate_response(msg="login fail!", code=1)


api.add_resource(LoginView, "/login")

在config里写好secretkey和过期时间

# 内部私钥
SECRET_KEY = "123456"
# 过期时间
EXPIRES_IN = "10"

libs/auth.py生成token函数放这里

from flask import current_app
from itsdangerous import TimedSerializer


# 生成token
def create_token(uid):
    # 生成token,第一个参数传入内部私钥,第二个参数有效期
    s = TimedSerializer(current_app.config["SECRET_KEY"], current_app.config["EXPIRES_IN"])
    token = s.dumps({"uid":uid})
    return token

【自学开发之旅】Flask-前后端联调-异常标准化返回_第1张图片
每次请求的token都不一样

pyjwt是web开发里专门用来生成token的库
pip install pyjwt
libs/auth.py

import jwt
from jwt.exceptions import ExpiredSignatureError, InvalidSignatureError

#用jwt生成token库
def create_token(uid):
    expir_in = current_app.config.get("EXPIRES_IN")
    payload = {"uid":uid, "exp":time.time() + expir_in}
    print(payload)
    key = current_app.config["SECRET_KEY"]
    token = jwt.encode(payload, key)
    return token

过期时间改回整形config/settings.py

# 过期时间
EXPIRES_IN = 600

【自学开发之旅】Flask-前后端联调-异常标准化返回_第2张图片
这个token是base64加密

{
    "code": 0,
    "msg": "login success!",
    "data": {
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjMsImV4cCI6MTY5NDkzMjIyOS4zNDM5MTF9.03zt-xxAvgJ487Hwfk3nyCa-vq0ml3kPcEo3SDT-UOc",
        "username": "jd2"
    }
}

Header
Payload
{“alg”:“HS256”,“typ”:“JWT”}{“uid”:3,“exp”:1694932229.343911}

Signature
为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。
例如:

HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)

服务端验证:拿到token之后,按照里面的header+payload+服务端保存的secretkey一起进行相同算法加密。得到新的签名,再和客户端传递的签名比较,一致就验证通过

两种验证:api验证,token验证
#验证token
libs/auth.py

def auth_required(func):
    def inner(*args, **kwargs):
        api_flag = request.args.get("api")
        if (api_flag == "1" and api_auth()) or token_auth():
            return func(*args, **kwargs)
        else:
            return "认证失败"
    return inner


# 验证token
def token_auth():
    token = request.headers.get("token")
    if token:
        try:
            print(time.time())
            jwt_obj = jwt.decode(token, current_app.config.get("SECRET_KEY"),
                                 algorithms=["HS256"])
        except InvalidSignatureError as e:
            print("token不合法", e)
            return False
        except ExpiredSignatureError as e:
            print("token过期", e)
            return False
        return True
    else:
        return False

首先POST访问127.0.0.1:9000/v1/login
得到token,复制粘贴,然后GET访问127.0.0.1:9000/v1/product,HEADERS中代token字段访问
【自学开发之旅】Flask-前后端联调-异常标准化返回_第3张图片
前后端联调

前端流程

异常标准化返回
libs/error_code.py

from werkzeug.exceptions import HTTPException

class APIException(HTTPException):
    code = 500   #http状态码
    message = "fail!"  #状态描述信息
    status_code = 9999 # 程序状态
    def __init__(self, message=None, code=None, status_code = None):
        if message:
            self.message = message
        if code:
            self.code = code
        if status_code:
            self.status_code = status_code
        super(APIException, self).__init__()
    def get_body(self, environ = None, scope = None) -> str:
        body = dict(
            message = self.message,
            code = self.status_code
        )
        import json
        content = json.dumps(body)
        return content

    def get_headers(self, environ = None, scope = None,) :
        return [('content-Type', 'application/json')]

#自定义异常类
class APIAuthorizedException(APIException):
    message = "API授权认证失败"
    status_code = 10002
    code = 401

class FormValidateException(APIException):
    message = "表单验证失败"
    status_code = 10003

class TokenFailException(APIException):
    message = "token不合法,验证失败"
    status_code = 10005
    code = 401

libs/handler.py

from flask_restful import HTTPException
from libs.error_code import APIException

#无论什么异常  都返回APIException
def default_error_handler(ex):
    if isinstance(ex, APIException):
        return ex
    if isinstance(ex, HTTPException):
        code = ex.code
        message = ex.description
        status_code = 10001
        return APIException(code = code, message=message, status_code=status_code)
    return APIException()
from libs.handler import default_error_handler

#异常标准化返回
api.handle_error = default_error_handler

#异常标准化返回
handle_error 原本处理异常情况返回的一个方法
当发生异常情况时,会自动调用handle_error函数处理异常返回
【自学开发之旅】Flask-前后端联调-异常标准化返回_第4张图片
修改libs/auth.py

from libs.error_code import APIAuthorizedException

def auth_required(func):
    def inner(*args, **kwargs):
        api_flag = request.args.get("api")
        if (api_flag == "1" and api_auth()) or token_auth():
            return func(*args, **kwargs)
        else:
            raise APIAuthorizedException
    return inner

【自学开发之旅】Flask-前后端联调-异常标准化返回_第5张图片

你可能感兴趣的:(flask,python,后端)