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
相关产品推荐
相关产品推荐

