diff --git a/configs.py b/configs.py index 68974d1..d6acc5f 100644 --- a/configs.py +++ b/configs.py @@ -1,4 +1,5 @@ import os +from datetime import timedelta class BaseConfig: @@ -8,6 +9,9 @@ class BaseConfig: ROOT_PATH = os.path.dirname(os.path.abspath(__file__)) + JWT_TOKEN_LOCATION = ["headers", "cookies"] + JWT_ACCESS_TOKEN_EXPIRES = timedelta(days=7) + class DevelopmentConfig(BaseConfig): """开发配置""" diff --git a/pear_admin/apis/passport.py b/pear_admin/apis/passport.py index 51476bf..18bb95c 100644 --- a/pear_admin/apis/passport.py +++ b/pear_admin/apis/passport.py @@ -1,8 +1,48 @@ -from flask import Blueprint +from flask import Blueprint, make_response, redirect, request +from flask_jwt_extended import ( + create_access_token, + create_refresh_token, + jwt_required, + set_access_cookies, + set_refresh_cookies, + unset_access_cookies, + unset_refresh_cookies, +) + +from pear_admin.extensions import db +from pear_admin.orms import UserORM passport_api = Blueprint("passport", __name__) @passport_api.post("/login") def login_in(): - return {"message": "登录成功", "code": 0} + data = request.get_json() + + user: UserORM = db.session.execute( + db.select(UserORM).where(UserORM.username == data["username"]) + ).scalar() + + if not user: + return {"message": "用户不存在", "code": -1}, 401 + if user.check_password(data["password"]): + return {"message": "用户密码错误", "code": -1}, 401 + + access_token = create_access_token(user) + refresh_token = create_refresh_token(user) + + response = make_response({"code": 0, "message": "登录成功"}) + + set_access_cookies(response, access_token) + set_refresh_cookies(response, refresh_token) + + return response + + +@passport_api.route("/logout", methods=["GET", "POST"]) +@jwt_required() +def logout(): + response = make_response(redirect("/login")) + unset_access_cookies(response) + unset_refresh_cookies(response) + return response diff --git a/pear_admin/extensions/init_jwt.py b/pear_admin/extensions/init_jwt.py index 0bad009..7b1a881 100644 --- a/pear_admin/extensions/init_jwt.py +++ b/pear_admin/extensions/init_jwt.py @@ -1,3 +1,4 @@ +from flask import redirect from flask_jwt_extended import JWTManager from pear_admin.orms.user import UserORM @@ -14,3 +15,13 @@ def user_identity_lookup(user): def user_lookup_callback(_jwt_header, jwt_data): identity = jwt_data["sub"] return UserORM.query.filter_by(id=identity).one_or_none() + + +@jwt.expired_token_loader +def expired_token_callback(): + return redirect("/login") + + +@jwt.unauthorized_loader +def missing_token_callback(error): + return redirect("/login") diff --git a/pear_admin/views/index.py b/pear_admin/views/index.py index b371d99..4a2c4e3 100644 --- a/pear_admin/views/index.py +++ b/pear_admin/views/index.py @@ -1,14 +1,17 @@ from flask import Blueprint, render_template +from flask_jwt_extended import jwt_required index_bp = Blueprint("index", __name__) @index_bp.route("/") +@jwt_required() def index(): return render_template("index.html") @index_bp.route("/login.html") +@index_bp.route("/login") def login(): return render_template("login.html") diff --git a/templates/index.html b/templates/index.html index dce2844..62a6121 100644 --- a/templates/index.html +++ b/templates/index.html @@ -118,7 +118,7 @@ admin.logout(function () { popup.success("注销成功", function () { - location.href = "./login.html"; + location.href = "/api/v1/logout"; }); // 清空 tabs 缓存 diff --git a/templates/login.html b/templates/login.html index 60743eb..f435e53 100644 --- a/templates/login.html +++ b/templates/login.html @@ -22,7 +22,7 @@ -