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

Django如何配置多会话表为Account模型生成二次认证会话Cookie

Django双用户模型双会话认证实现方案

1. 定义独立的Account业务会话模型

复用Django内置的AbstractBaseSession抽象基类创建专属Account的会话表,和默认的Auth User临时会话表物理隔离:

# myapp/models.py
from django.contrib.sessions.models import AbstractBaseSession
from django.db import models
from django.contrib.auth.models import PermissionsMixin

# 你原有的Account模型
class Account(PermissionsMixin):
    auth_user = models.ForeignKey("auth.User", on_delete=models.CASCADE)
    # 其他业务字段...

# Account专属会话模型
class AccountSession(AbstractBaseSession):
    # 可选字段:绑定account_id方便后续查询活跃会话、批量下线等操作
    account_id = models.IntegerField(null=True, db_index=True)
    
    class Meta:
        db_table = "account_session"

创建完成后执行python manage.py makemigrations和python manage.py migrate生成新的会话表。
默认的Django内置Session表直接用作Auth User临时认证的存储载体,不需要额外修改。

2. 实现Account专属会话引擎

自定义会话引擎绑定新建的AccountSession模型,继承Django默认的数据库会话逻辑减少重复开发:

# myapp/sessions/backends.py
from django.contrib.sessions.backends.db import SessionStore as DBSessionStore
from myapp.models import AccountSession

class AccountSessionStore(DBSessionStore):
    # 绑定自定义会话模型
    @classmethod
    def get_model_class(cls):
        return AccountSession
    
    # 重写save方法自动同步account_id到表字段
    def save(self, must_create=False):
        if "account_id" in self:
            self.model.objects.filter(pk=self.session_key).update(account_id=self["account_id"])
        super().save(must_create=must_create)

3. 配置双Cookie参数避免冲突

在settings.py中分别配置两套会话的Cookie规则,从路径、名称、有效期维度完全隔离:

# settings.py

# 内置会话配置:对应Auth User临时认证的auth cookie
SESSION_COOKIE_NAME = "auth_sessionid"
SESSION_COOKIE_PATH = "/auth/" # 仅认证相关接口携带,不会泄露到业务路径
SESSION_COOKIE_AGE = 30 * 60 # 30分钟有效期,仅满足账号选择流程
SESSION_EXPIRE_AT_BROWSER_CLOSE = False

# 自定义Account业务会话配置
ACCOUNT_SESSION_COOKIE_NAME = "account_sessionid"
ACCOUNT_SESSION_COOKIE_PATH = "/" # 全业务路径携带
ACCOUNT_SESSION_COOKIE_AGE = 7 * 24 * 60 * 60 # 7天有效期
ACCOUNT_SESSION_ENGINE = "myapp.sessions.backends.AccountSessionStore"

注意:必须保证两套Cookie的name和path不重叠,避免出现Cookie互相覆盖的问题

4. 适配登录流程逻辑

4.1 Auth User初次认证

该步骤直接使用Django默认的authenticate和login方法即可,认证通过后生成的auth_sessionid Cookie仅能访问/auth路径下的接口,无法访问业务资源。

4.2 查询关联Account列表

校验Auth User会话有效性后,取出当前登录的Auth User ID,查询关联的所有Account列表返回给前端供用户选择。

4.3 生成Account业务会话

用户提交选中的account_id后,先校验Auth会话合法性和Account归属关系,再手动生成Account会话和对应Cookie:

# myapp/views.py
from django.conf import settings
from django.utils.module_loading import import_string
from rest_framework.response import Response
from myapp.models import Account

AccountSessionStore = import_string(settings.ACCOUNT_SESSION_ENGINE)

def select_account(request):
    # 校验Auth会话合法性
    if not request.user.is_authenticated:
        return Response(status=401)
    account_id = request.data.get("account_id")
    # 校验Account属于当前登录的Auth User
    try:
        account = Account.objects.get(id=account_id, auth_user=request.user)
    except Account.DoesNotExist:
        return Response(status=403)
    
    # 初始化Account会话
    account_session = AccountSessionStore()
    account_session["account_id"] = account.id
    # 可选:预存权限信息减少后续DB查询
    account_session["permissions"] = list(account.get_all_permissions())
    account_session.save()
    
    # 写入Account Cookie到响应
    response = Response(status=200)
    response.set_cookie(
        key=settings.ACCOUNT_SESSION_COOKIE_NAME,
        value=account_session.session_key,
        max_age=settings.ACCOUNT_SESSION_COOKIE_AGE,
        path=settings.ACCOUNT_SESSION_COOKIE_PATH,
        secure=request.is_secure(),
        httponly=True,
        samesite="Lax"
    )
    return response

5. 业务接口认证适配

自定义中间件校验Account会话,替换默认的Auth认证逻辑,所有业务接口都通过该中间件校验权限:

# myapp/middlewares.py
from django.conf import settings
from django.utils.module_loading import import_string
from rest_framework.response import Response
from myapp.models import Account

AccountSessionStore = import_string(settings.ACCOUNT_SESSION_ENGINE)

class AccountAuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # 跳过/auth路径下的认证接口
        if request.path.startswith("/auth/"):
            return self.get_response(request)
        
        # 校验Account Cookie有效性
        account_session_key = request.COOKIES.get(settings.ACCOUNT_SESSION_COOKIE_NAME)
        if not account_session_key:
            return Response(status=401)
        account_session = AccountSessionStore(session_key=account_session_key)
        if not account_session.exists(account_session_key):
            return Response(status=401)
        
        # 注入当前Account实例到request对象,业务逻辑直接调用
        request.account = Account.objects.get(id=account_session["account_id"])
        request.account_permissions = account_session["permissions"]
        return self.get_response(request)

将该中间件添加到settings.py的MIDDLEWARE列表中,放在django.middleware.common.CommonMiddleware之后即可。

6. 权限适配

因为Account模型继承了PermissionsMixin,你可以自定义权限装饰器校验request.account的权限,也可以在中间件中将request.user临时替换为Account实例,直接复用Django原生的权限校验逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 19:36:03