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

Django中cAdmin应用限制仅使用自定义认证后端的问题

Django cAdmin应用认证后端限制问题

我有一个用于企业用户管理的Django应用cAdmin,Django超级用户存储在User Model中,用于创建企业管理员。自定义了MyCustomAuthBackend认证后端,仅校验CompanyAdmin model的凭证,但当前使用User模型的凭证也能登录。经排查,原因是第一个后端验证失败后会自动跳转至ModelBackend。尝试过ChatGPT生成的中间件但无效,需要解决cAdmin应用中第一个后端验证失败时不跳转至第二个后端的问题。

自定义认证后端代码

from django.contrib.auth.backends import BaseBackend
from .models import CompanyAdmin
from django.contrib.auth.hashers import make_password,check_password

class MyCustomAuthBackend(BaseBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = CompanyAdmin.objects.get(adminName=username)
            print(user.adminPassword,"      ",make_password(password))
            if check_password(password, user.adminPassword):
                print("worked password", user.adminPassword, password)
                #user.is_authenticated = True
                print(user,"printer duser")
                return user
            
        except CompanyAdmin.DoesNotExist:
            return None 
        return None

登录视图代码

from django.shortcuts import render,HttpResponse
from django.views.decorators.cache import cache_control
from User.models import TicketDetails,Tickets,Category
from cAdmin.decorators import signin_required
from django.contrib.auth import authenticate,login,logout

@cache_control(no_cache=True, must_revalidate=True, no_store=True) 
def Login(request,id=None):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        print("login view password")
        user=authenticate(request,username=username,password=password)
        print(user)
        if user:
            print(user)
            login(request,user)
            context = {'LoggedUser': user}
            return render(request,'cAdmin/adminDashboard.html',context) 
        else:
            return render(request, 'cAdmin/index.html',{'flag': 1})

    request.session.flush()
    return render(request, 'cAdmin/index.html',{})

认证后端配置

AUTHENTICATION_BACKENDS = [
 'cAdmin.backends.MyCustomAuthBackend',
 'django.contrib.auth.backends.ModelBackend',
]

尝试过的无效中间件

from django.contrib.auth.backends import ModelBackend

class MyAppAuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Check the current app and set the authentication backend accordingly
        if request.path.startswith('/cAdmin/'):
            print("Auth workeeeeeeeeeeeed")
            request.backend = 'cAdmin.backends.MyCustomAuthBackend'
        elif request.path.startswith('/'):

            request.backend = 'django.contrib.auth.backends.ModelBackend'
            print("lhglhflghlfshdglhfdlh")
            

        response = self.get_response(request)
        return response

解决方案

方案1:在登录视图中直接使用自定义后端认证(推荐)

修改登录视图,跳过全局authenticate函数,直接实例化自定义后端进行校验,这样就不会触发后续的ModelBackend验证:

from django.shortcuts import render,HttpResponse
from django.views.decorators.cache import cache_control
from User.models import TicketDetails,Tickets,Category
from cAdmin.decorators import signin_required
from django.contrib.auth import login,logout
from cAdmin.backends import MyCustomAuthBackend  # 导入自定义后端

@cache_control(no_cache=True, must_revalidate=True, no_store=True) 
def Login(request,id=None):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        print("login view password")
        # 直接使用自定义后端执行认证逻辑
        backend = MyCustomAuthBackend()
        user = backend.authenticate(request, username=username, password=password)
        print(user)
        if user:
            print(user)
            # 登录时必须指定backend参数,避免后续认证环节出错
            login(request, user, backend='cAdmin.backends.MyCustomAuthBackend')
            context = {'LoggedUser': user}
            return render(request,'cAdmin/adminDashboard.html',context) 
        else:
            return render(request, 'cAdmin/index.html',{'flag': 1})

    request.session.flush()
    return render(request, 'cAdmin/index.html',{})

方案2:动态调整全局认证后端(需注意线程安全)

通过中间件临时修改全局AUTHENTICATION_BACKENDS配置,针对/cAdmin/路径只保留自定义后端:

from django.conf import settings
from django.utils.deprecation import MiddlewareMixin

class CAdminAuthBackendMiddleware(MiddlewareMixin):
    def process_request(self, request):
        if request.path.startswith('/cAdmin/'):
            # 保存原后端配置
            self.original_backends = settings.AUTHENTICATION_BACKENDS
            # 临时设置仅使用自定义后端
            settings.AUTHENTICATION_BACKENDS = ['cAdmin.backends.MyCustomAuthBackend']
        else:
            # 非cAdmin路径恢复原配置
            if hasattr(self, 'original_backends'):
                settings.AUTHENTICATION_BACKENDS = self.original_backends

    def process_response(self, request, response):
        # 响应完成后确保恢复原配置,避免影响其他请求
        if hasattr(self, 'original_backends'):
            settings.AUTHENTICATION_BACKENDS = self.original_backends
        return response

注意:此方案修改全局设置,在多线程/多进程的服务器环境下可能存在线程安全问题,需谨慎使用。


无效中间件原因说明

之前的中间件仅给request对象添加了backend属性,但Django的authenticate函数并不会读取该属性,而是遍历settings.AUTHENTICATION_BACKENDS中的所有后端依次验证,因此无法达到限制效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:34:56