fastapi:jinja2:把登录信息统一传递给模板

一,代码

在middleware中获取用户信息:

# 中间件:全自动解析登录态
# 1. 定义中间件类,必须继承 BaseHTTPMiddleware
class CustomAuthMiddleware(BaseHTTPMiddleware):
    async def dispatch(self,
                       request: Request,
                       call_next,
                       ):
        # 从cookie得到用户信息
        current_user = await get_current_user_from_cookie(request)

        if current_user is None:
            # 将结果挂载到 request.state,方便后续调用
            request.state.user = None
            request.state.is_authenticated = False

            response = await call_next(request)
            return response


        # 3. 生产环境核心:直接使用全局工厂创建独立的、短暂的会话
        try:
            async with AsyncSessionLocal() as db:
                # 1. 查询用户是否存在
                stmt = select(User).where(User.username == current_user['username'])
                result = await db.execute(stmt)
                user = result.scalar_one_or_none()

                if user is None:
                    cur_user = None
                else:
                    cur_user = {
                        'username':user.username,
                        'nickname': user.nickname,
                    }
        except Exception as e:
            # 生产环境中务必捕获数据库异常,防止连接泄漏或暴露敏感堆栈

            return JSONResponse(status_code=500, content={"detail": "Internal server error"})

        # 将结果挂载到 request.state,方便后续调用
        request.state.user = cur_user
        request.state.is_authenticated = cur_user is not None

        response = await call_next(request)
        return response

main中应用middleware

# 创建独立隔离的管理后台子应用
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")

# 启用中间件(不使用装饰器)
admin_app.add_middleware(CustomAuthMiddleware)

定义方法,把用户信息数据传递给模板 

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

# -----------------------------------------------------------
# 生产级封装:重写模板渲染方法,自动注入全局变量
def render_template( request: Request, template_name: str,context: dict = None):
    if context is None:
        context = {}

    # 自动把中间件解析出的用户信息,注入到 Jinja2 上下文中
    context["request"] = request
    context["current_user"] = getattr(request.state, "user", None)
    context["is_authenticated"] = getattr(request.state, "is_authenticated", False)

    return templates.TemplateResponse(
        request=request,
        name=template_name,
        context=context
    )

请求中用自定义的方法返回页面

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

    # 获取用户信息
    username = current_user['username']
    print("username:", username)

    cur_user = {
        'username': username,
        'nickname': '他人不错',
    }

    return render_template( request,
                            "account/info.html",
                            {
             "user": cur_user, "title": "登录"
        })

html页面:

<!-- index.html -->
{% extends "layout/base.html" %}

<!-- 重写标题块 -->
{% block title %}首页 - 我的网站{% endblock %}

<!-- 填充核心内容块 -->
{% block content %}
    <h1>欢迎来到首页!</h1>
    <!-- 核心判断:是否登录 -->
        {% if is_authenticated %}
<div>当前状态:已登录,用户名:{{current_user.username}}:</div>
            <span>欢迎回来,{{ current_user.nickname }} </span>
            <a href="/admin/account/logout">退出登录</a>
        {% else %}
            <div>当前状态:未登录:</div>
            <a href="/login">登录</a>
            <a href="/register">注册</a>
        {% endif %}
    <p>当前用户名:{{user['username']}}</p>
{% endblock %}

二,测试效果:

image

 

posted @ 2026-07-19 17:25  刘宏缔的架构森林  阅读(4)  评论(0)    收藏  举报