fastapi:管理后台:退出登录,并封装类似flask的flash函数

一,安装用到的库:

pip install itsdangerous

二,代码

python代码:

main.py中引入SessionMiddleware

# 创建独立隔离的管理后台子应用
admin_app = FastAPI(
    title="管理后台系统",
    dependencies=[Depends(verify_admin_user)]  # 👈 核心:作为子应用全局依赖
)
# 注册全局异常捕获
register_exception_handlers(admin_app)

# 🌟 必须挂载 Session 中间件,flash 消息才得以跨请求保存
admin_app.add_middleware(SessionMiddleware, secret_key="your-secure-secret-key")

temlates.py中添加用到的方法

# app/config/exts.py
from fastapi.templating import Jinja2Templates
from fastapi import FastAPI, Request, Form, status

# 在公共文件中声明模板实例
templates = Jinja2Templates(directory="app/admin/templates")

# ----------------- 🌟 核心:封装 Flash 函数 -----------------
def flash(request: Request, message: str, category: str = "info"):
    """向 Session 中写入一条闪现消息"""
    if "_messages" not in request.session:
        request.session["_messages"] = []
    request.session["_messages"].append({"message": message, "category": category})

def get_flashed_messages(request: Request):
    """从 Session 中取出所有闪现消息,并将其清空(Pop)"""
    return request.session.pop("_messages") if "_messages" in request.session else []

# 🌟 将获取消息的方法直接注入到 Jinja2 环境中,这样在 HTML 里就能直接调用
templates.env.globals.update(get_flashed_messages=get_flashed_messages)
# -----------------------------------------------------------

在共用的页面的head部分添加用到的html/css代码:

 <body>

  <!-- 🌟 核心:直接在 Jinja2 中循环读取并展示闪现消息 -->
    {% set messages = get_flashed_messages(request) %}
    {% if messages %}
<!-- 1. 浮动在页面最上层的容器 -->
    <div id="flash-container" style="position: fixed; top: 20px; left: 50%; transform: translateX(-50%); z-index: 9999; display: flex; flex-direction: column; gap: 10px; align-items: center; width: auto; min-width: 250px; max-width: 90%;">
        {% for msg in messages %}
            <!-- 2. 圆角、半透明(背景模糊)、阴影、自带淡入淡出动画的提示框 -->
            <div class="flash-toast {{ msg.category }}" style="
                padding: 12px 24px;
                border-radius: 8px;
                font-weight: 500;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                backdrop-filter: blur(8px); /* 🌟 毛玻璃效果 */
                -webkit-backdrop-filter: blur(8px);
                transition: opacity 0.4s ease, transform 0.4s ease; /* 🌟 动画过渡 */
                animation: slideIn 0.3s ease forwards;
            ">
                {{ msg.message }}
            </div>
        {% endfor %}
    </div>

    <!-- 3. 自定义样式(主要用于控制不同状态的半透明颜色) -->
    <style>
        /* 淡入动画 */
        @keyframes slideIn {
            from { opacity: 0; transform: translateY(-20px); }
            to { opacity: 1; transform: translateY(0); }
        }

        /* 成功提示:绿色半透明 */
        .flash-toast.success {
            background-color: rgba(212, 237, 218, 0.85);
            color: #155724;
            border: 1px solid rgba(195, 230, 203, 0.5);
        }
        /* 危险提示:红色半透明 */
        .flash-toast.danger {
            background-color: rgba(248, 215, 218, 0.85);
            color: #721c24;
            border: 1px solid rgba(245, 198, 203, 0.5);
        }
        /* 普通提示:蓝色半透明 */
        .flash-toast.info {
            background-color: rgba(209, 236, 241, 0.85);
            color: #0c5460;
            border: 1px solid rgba(190, 229, 235, 0.5);
        }
    </style>

    <!-- 4. 🌟 核心:1秒后自动淡出并销毁的 JS 脚本 -->
    <script>
        document.addEventListener("DOMContentLoaded", function() {
            const container = document.getElementById("flash-container");
            if (container) {
                // 1000毫秒(1秒)后触发淡出
                setTimeout(() => {
                    const toasts = container.querySelectorAll('.flash-toast');
                    toasts.forEach(toast => {
                        toast.style.opacity = '0';
                        toast.style.transform = 'translateY(-30px)'; // 稍微往上飘走
                    });

                    // 等待 400ms 动画结束后,彻底从 DOM 树中移除容器,不占空间
                    setTimeout(() => container.remove(), 400);
                }, 1500);
            }
        });
    </script>
    {% endif %}

 代码中调用:

# 登出
@router.get("/logout")
def account_logout(
    request: Request,
    # 挂载强制登录依赖,未登录的用户根本进不来
    current_user: dict = Depends(admin_login_required)
):

    # 弹出窗口提示已退出
    flash(request, "已成功退出登录", category="success")

    # 创建response
    response = RedirectResponse(
        url="/admin/account/login",
        status_code=status.HTTP_302_FOUND
    )

    # 清除浏览器的安全 Cookie
    response.delete_cookie(
        key=COOKIE_NAME,
        path="/",  # 必须与你 set_cookie 时的路径一致(默认是 "/")
        httponly=True,  # 安全策略保持一致
        samesite="lax"
    )

    return response

 

三,测试效果

image

 

posted @ 2026-07-18 23:55  刘宏缔的架构森林  阅读(8)  评论(0)    收藏  举报