如何使用两个 Django 身份验证后端并根据使用的后端提供不同的访问权限?
How can I use two Django authentication backends and give different access depending on which is used?
我有两个不同的 类 用户用于基于 Django 的事件注册系统。我们称他们为“注册人”和“职员”吧。
这两者并不相互排斥,我认为没有理由不对两者使用相同的用户模型类(用标志来区分它们)。
注册者可以通过向第三方验证身份来登录 API,然后可以注册活动。
职员可以访问 Django Admin,并且可以管理事件。我不相信第三方 API 能够充分验证具有 Staffer 访问权限的人的身份,因为虽然它确实要求提供个人信息来识别某人,但它不会要求任何像密码一样安全的东西。因此,我希望工作人员输入密码而不是通过第三方进行身份验证 API.
我发现我可以 write a custom auth backend in Django, and I can customise the default User model 满足我对上述标志的需求(尽管我怀疑默认的 is_staff
)标志可能就足够了)。
不幸的是,虽然我知道我可以使用多个身份验证后端,但我仍然无法解决如何:
a) 确定要使用的身份验证后端(例如,在前端使用 Registrant 身份验证后端,在 Admin 中使用 Staffer 身份验证后端)
b) 仅 允许通过 Staffer auth 后端认证的用户访问 Admin
谁能给我指出正确的方向?
抱歉缺少代码;我正在从头开始重新设计 auth 系统(因为以前的版本真的很糟糕)我不知道从哪里开始。
编辑:在 Django Multiple Authentication Backends Based On Status 有 一些 有用的信息,但是因为我想为用户 类 使用相同的用户模型,并且两个 auth 后端都会请求不同类型的凭据(例如,一个请求密码,另一个不请求),我需要更多地考虑如何解决这个问题。
如果我有这个问题,我会为他们每个人使用一个继承模型,将用户名作为员工的默认登录名和注册人的电子邮件,同时扩展 BaseUser 模型。
为了 select 使用 Auth 后端,我只需设置一个复选框或构建不同的 URL 即可登录。
“确定要使用哪个身份验证后端”的答案非常简单,您根本不需要这样做。正如 documentation when you call the authenticate()
function 中指定的那样,Django 依次尝试每个 AUTHENTICATION_BACKENDS
直到一个 return 成为用户或引发 PermissionDenied
异常。
此外,如果您查看默认后端的 code [GitHub],如果没有传入用户名或密码,它只是 returns None
。您需要以类似的方式实现您的后端,这样如果您期望的凭据没有传入,您应该 return None
并让其他(可能的)后端处理它。
对于“仅允许通过 Staffer 身份验证后端进行身份验证的用户访问管理员”,您可以override the default admin site and override the has_permission
method:
from django.contrib import admin
from django.contrib.auth import BACKEND_SESSION_KEY
class MyAdminSite(admin.AdminSite):
def has_permission(self, request):
"""
Return True if the given HttpRequest has permission to view
*at least one* page in the admin site.
"""
try:
backend_path = request.session[BACKEND_SESSION_KEY]
staffer_backend = backend_path == "path.to.StafferBackend"
return request.user.is_active and request.user.is_staff and staffer_backend
except KeyError:
return False
然后在您的某个应用程序的 apps.py
中:
from django.contrib.admin.apps import AdminConfig
class MyAdminConfig(AdminConfig):
default_site = 'myproject.admin.MyAdminSite'
最后在您的设置中替换 'django.contrib.admin'
:
INSTALLED_APPS = [
...
'myproject.apps.MyAdminConfig', # replaces 'django.contrib.admin'
...
]
我有两个不同的 类 用户用于基于 Django 的事件注册系统。我们称他们为“注册人”和“职员”吧。
这两者并不相互排斥,我认为没有理由不对两者使用相同的用户模型类(用标志来区分它们)。
注册者可以通过向第三方验证身份来登录 API,然后可以注册活动。
职员可以访问 Django Admin,并且可以管理事件。我不相信第三方 API 能够充分验证具有 Staffer 访问权限的人的身份,因为虽然它确实要求提供个人信息来识别某人,但它不会要求任何像密码一样安全的东西。因此,我希望工作人员输入密码而不是通过第三方进行身份验证 API.
我发现我可以 write a custom auth backend in Django, and I can customise the default User model 满足我对上述标志的需求(尽管我怀疑默认的 is_staff
)标志可能就足够了)。
不幸的是,虽然我知道我可以使用多个身份验证后端,但我仍然无法解决如何:
a) 确定要使用的身份验证后端(例如,在前端使用 Registrant 身份验证后端,在 Admin 中使用 Staffer 身份验证后端) b) 仅 允许通过 Staffer auth 后端认证的用户访问 Admin
谁能给我指出正确的方向?
抱歉缺少代码;我正在从头开始重新设计 auth 系统(因为以前的版本真的很糟糕)我不知道从哪里开始。
编辑:在 Django Multiple Authentication Backends Based On Status 有 一些 有用的信息,但是因为我想为用户 类 使用相同的用户模型,并且两个 auth 后端都会请求不同类型的凭据(例如,一个请求密码,另一个不请求),我需要更多地考虑如何解决这个问题。
如果我有这个问题,我会为他们每个人使用一个继承模型,将用户名作为员工的默认登录名和注册人的电子邮件,同时扩展 BaseUser 模型。
为了 select 使用 Auth 后端,我只需设置一个复选框或构建不同的 URL 即可登录。
“确定要使用哪个身份验证后端”的答案非常简单,您根本不需要这样做。正如 documentation when you call the authenticate()
function 中指定的那样,Django 依次尝试每个 AUTHENTICATION_BACKENDS
直到一个 return 成为用户或引发 PermissionDenied
异常。
此外,如果您查看默认后端的 code [GitHub],如果没有传入用户名或密码,它只是 returns None
。您需要以类似的方式实现您的后端,这样如果您期望的凭据没有传入,您应该 return None
并让其他(可能的)后端处理它。
对于“仅允许通过 Staffer 身份验证后端进行身份验证的用户访问管理员”,您可以override the default admin site and override the has_permission
method:
from django.contrib import admin
from django.contrib.auth import BACKEND_SESSION_KEY
class MyAdminSite(admin.AdminSite):
def has_permission(self, request):
"""
Return True if the given HttpRequest has permission to view
*at least one* page in the admin site.
"""
try:
backend_path = request.session[BACKEND_SESSION_KEY]
staffer_backend = backend_path == "path.to.StafferBackend"
return request.user.is_active and request.user.is_staff and staffer_backend
except KeyError:
return False
然后在您的某个应用程序的 apps.py
中:
from django.contrib.admin.apps import AdminConfig
class MyAdminConfig(AdminConfig):
default_site = 'myproject.admin.MyAdminSite'
最后在您的设置中替换 'django.contrib.admin'
:
INSTALLED_APPS = [
...
'myproject.apps.MyAdminConfig', # replaces 'django.contrib.admin'
...
]