You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中如何在访问实际视图页面前先展示主密码验证页面

实现方案

核心逻辑是通过装饰器拦截受保护的请求,结合session记录主密码校验状态,校验通过后自动跳转回原目标地址,具体实现步骤如下:

步骤1:编写主密码校验装饰器

所有需要校验主密码的视图都可以复用这个装饰器,逻辑是先检查session中是否有未过期的校验通过标记,没有的话就跳转到密码校验页,同时携带当前请求地址作为跳转参数:

from django.shortcuts import redirect
from functools import wraps
from datetime import datetime, timedelta

def require_master_password(view_func):
    @wraps(view_func)
    def _wrapped_view(request, *args, **kwargs):
        # 读取session中的校验状态和过期时间
        verified = request.session.get('master_password_verified', False)
        expire_ts = request.session.get('master_password_expire', 0)
        current_ts = datetime.now().timestamp()

        # 校验未通过或已过期,跳转到校验页
        if not verified or current_ts > expire_ts:
            return redirect(f"/check-master-password/?next={request.path}")
        return view_func(request, *args, **kwargs)
    return _wrapped_view

步骤2:修改密码校验视图

调整后的视图会接收跳转目标地址,校验通过后将状态写入session,再跳回原目标页面:

def check_master_password_view(request):
    page = 'check'
    profile = request.user.profile
    # 读取跳转目标,默认跳转到用户首页
    next_url = request.GET.get('next', '/')

    if request.method == "POST":
        # 优先从POST参数中拿跳转地址(从表单隐藏字段传递)
        next_url = request.POST.get('next', next_url)
        checked = check_master_password(request.POST['password'], profile.master_password)
        if checked:
            # 校验通过,写入session,默认设置10分钟有效期,可自行调整
            request.session['master_password_verified'] = True
            request.session['master_password_expire'] = (datetime.now() + timedelta(minutes=10)).timestamp()
            return redirect(next_url)
        else:
            messages.error(request, 'You entered wrong password !')
    
    context = {
        'page': page,
        'next_url': next_url
    }
    return render(request, 'users/create_or_check_master_password.html', context)

步骤3:修改密码校验模板

在create_or_check_master_password.html的表单中添加隐藏字段,传递跳转目标地址:

<form method="POST">
    {% csrf_token %}
    <!-- 新增隐藏字段传递next参数 -->
    <input type="hidden" name="next" value="{{ next_url }}">
    <!-- 原有密码输入等表单内容 -->
</form>

步骤4:给受保护的视图添加装饰器

比如你的日记详情、修改、删除视图,直接加装饰器即可:

@require_master_password
def detail_diary_view(request, pk):
    profile = request.user.profile
    diary = profile.diary_set.get(id=pk)
    diary.diary = decrypt_diary(request, diary.diary)
    context = {
        'diary': diary
    }
    return render(request, 'diary/detail_diary.html', context)

额外优化建议

  • 用户登出时记得清空session中的校验标记,避免共用设备时的安全风险,可以在登出逻辑中加入:
    request.session.pop('master_password_verified', None)
    request.session.pop('master_password_expire', None)
    
  • 如果使用类视图,用method_decorator把装饰器绑定到dispatch方法即可生效。

内容的提问来源于stack exchange,提问作者A.Emre SAVAŞ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 21:06:01