You need to enable JavaScript to run this app. 如何在Django中为不同登录用户设置差异化会话过期时间
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中为不同登录用户设置差异化会话过期时间

Django 实现不同用户自定义单日会话时长方案

以下是完整实现步骤,覆盖从数据存储到逻辑校验的全流程:

1. 新增用户使用时长配置模型

首先扩展用户关联模型,存储管理员配置的时长、使用记录、锁定状态等数据:

from django.db import models
from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver

User = get_user_model()

class UserUsageProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="usage_profile")
    daily_allowed_hours = models.IntegerField(default=0, help_text="单日允许使用时长,单位:小时,0代表不限制")
    today_used_seconds = models.IntegerField(default=0, help_text="当日已使用秒数")
    last_active_date = models.DateField(null=True, blank=True, help_text="上次活跃日期")
    last_request_time = models.DateTimeField(null=True, blank=True, help_text="上次请求时间")
    is_locked = models.BooleanField(default=False, help_text="时长耗尽是否锁定")

# 自动为新创建的用户生成使用配置
@receiver(post_save, sender=User)
def create_usage_profile(sender, instance, created, **kwargs):
    if created:
        UserUsageProfile.objects.create(user=instance)

2. 基础配置调整

修改settings.py添加必要配置:

MIDDLEWARE = [
    # ... 其他默认中间件
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    # 自定义时长校验中间件,必须放在Session和认证中间件之后
    'yourapp.middlewares.UserUsageLimitMiddleware',
]

# 每次请求都更新会话,确保活跃状态实时同步
SESSION_SAVE_EVERY_REQUEST = True

3. 核心校验中间件实现

通过中间件拦截所有用户请求,实时计算使用时长、判断过期逻辑:

import datetime
from django.shortcuts import redirect
from django.contrib.auth import logout
from django.urls import reverse

class UserUsageLimitMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # 无需校验的路径白名单,避免死循环
        self.exempt_paths = [
            reverse('login'),
            reverse('admin:index'),
            '/static/',
            '/favicon.ico'
        ]

    def __call__(self, request):
        # 跳过白名单路径
        for path in self.exempt_paths:
            if request.path.startswith(path):
                return self.get_response(request)
        
        # 仅处理已登录的普通用户,管理员可按需设置是否受限制
        if request.user.is_authenticated and not request.user.is_staff:
            profile = request.user.usage_profile
            now = datetime.datetime.now()
            today = now.date()

            # 已锁定用户直接强制登出
            if profile.is_locked:
                logout(request)
                return redirect(f"{reverse('login')}?error=账号已锁定,请联系管理员授权")
            
            # 新日期重置当日使用时长
            if profile.last_active_date != today:
                profile.today_used_seconds = 0
                profile.last_active_date = today
            
            # 累计两次请求间隔的使用时长
            if profile.last_request_time:
                time_delta = now - profile.last_request_time
                profile.today_used_seconds += int(time_delta.total_seconds())
            
            # 时长耗尽锁定账号并强制登出
            if profile.daily_allowed_hours > 0 and profile.today_used_seconds >= profile.daily_allowed_hours * 3600:
                profile.is_locked = True
                profile.save()
                logout(request)
                return redirect(f"{reverse('login')}?error=今日使用时长已耗尽,请联系管理员重新授权")
            
            # 更新最新请求时间
            profile.last_request_time = now
            profile.save()
        
        return self.get_response(request)

4. 登录环节增加锁定校验

避免用户时长耗尽后重新登录,自定义登录表单增加校验逻辑:

from django.contrib.auth.forms import AuthenticationForm
from django import forms

class CustomLoginForm(AuthenticationForm):
    def confirm_login_allowed(self, user):
        super().confirm_login_allowed(user)
        if not user.is_staff and user.usage_profile.is_locked:
            raise forms.ValidationError("您的账号已被锁定,请联系管理员重新授权")

将自定义表单配置到登录视图即可生效。

5. 管理员后台配置入口

将时长配置模型注册到Django Admin,方便管理员调整用户时长、解锁账号:

from django.contrib import admin
from .models import UserUsageProfile

@admin.register(UserUsageProfile)
class UserUsageProfileAdmin(admin.ModelAdmin):
    list_display = ['user', 'daily_allowed_hours', 'today_used_seconds', 'is_locked', 'last_active_date']
    list_filter = ['is_locked', 'last_active_date']
    search_fields = ['user__username', 'user__email']
    # 允许管理员编辑的字段
    fields = ['user', 'daily_allowed_hours', 'today_used_seconds', 'is_locked']

注意事项

  • 分布式部署场景下建议将会话存储到Redis等统一缓存服务,避免多实例会话不同步
  • 可根据需求扩展剩余时长告警逻辑,比如剩余10%时长时发送站内信提醒用户
  • 如果需要精确到秒级校验,可以将中间件的时间差计算逻辑调整为更细的粒度

内容的提问来源于stack exchange,提问作者Dhatri Kapuriya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 03:45:03