注册联调:
前端修改:
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
每次请求的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
这个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字段访问
前后端联调
前端流程
异常标准化返回
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函数处理异常返回
修改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