Django一个项目多个身份验证后端

21

我有一个用Django编写的应用程序,我需要扩展它并将其他解决方案作为“应用程序”包含在此应用程序中。

例如,要集成的我的应用程序名为“my_new_app”,但主要应用程序已经编写了后端身份验证,我不能使用它。

我有一个MySQL数据库供查询,而主要应用程序大多使用Cassandra和Redis。

是否有任何方法可以为新应用程序“my_new_app”使用单独的身份验证后端并在同一域中运行两个应用程序?

5个回答

49

您可以使用多个认证后端。只需在Django项目的settings.py中设置AUTHENTICATION_BACKENDS,列出您想要使用的后端实现即可。例如,我经常将OpenID认证与标准的Django认证结合使用,就像在我的settings.py中这样设置:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'django_openid_auth.auth.OpenIDBackend',
    )
在这个例子中,Django首先尝试使用django.contrib.auth.backends.ModelBackend进行身份验证,这是Django的默认后端。如果失败,则继续使用下一个后端django_openid_auth.auth.OpenIDBackend
请注意,您的自定义后端必须在Django可见的路径上。在此示例中,我需要将django_openid_auth添加到INSTALLED_APPS中,否则Django将无法导入并将其用作后端。
另请阅读相关文档,它写得非常好,易于理解:https://docs.djangoproject.com/en/dev/topics/auth/customizing/

9

我之前遇到过这个问题。这是我所使用的代码。

这是在api/backend.py中的身份验证后端。

from django.contrib.auth.models import User

class EmailOrUsernameModelBackend(object):
    def authenticate(self, username=None, password=None):
        if '@' in username:
            kwargs = {'email': username}
        else:
             kwargs = {'username': username}
        try:
            user = User.objects.get(**kwargs)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

这是我的settings.py文件。

AUTHENTICATION_BACKENDS = (
    'api.backend.EmailOrUsernameModelBackend',
    'django.contrib.auth.backends.ModelBackend',
)

这段代码将使您能够在Django管理界面中使用电子邮件对默认Django用户进行身份验证。


1
虽然你的解决方案也不错,但它并没有完全满足我的需求。我会在几个小时内发布我的解决方案。顺便说一句,我从你的解决方案中得到了灵感,所以给你一个赞。 - Rai Muhammad Ehtisham
如果用户名可以包含“@”,那么使用if '@' in username:来识别用户名是否为电子邮件是一种相当糟糕的方法。你应该至少使用模式匹配或在源代码中确定所选选项。 - vintagexav
2
不要使用 if '@' in username:,而是像这样使用 django.core.validators.validate_emaildef validateEmail(email): try: validate_email(email) return True except ValidationError: return False - M.Void
或者干脆不允许在用户名中使用“@”... 如果您允许在用户名中同时使用“@”和“.”,那么无论您的验证有多严格,都会出现需要解决的歧义问题(因为在此模式下,无限数量的有效用户名也是有效的电子邮件)。您可以引入一些优先级来解决这个问题,但如果您使用户名与有效的电子邮件地址不相交(通过禁止在用户名中使用“@”),那么可能更容易理解。然后,这个解决方案就可以了(尽管我仍然会在检查“@”之后验证电子邮件地址)。 - DylanYoung

2
使用多个后端认证非常简单。您只需要了解Django应用程序的工作流程即可。
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.Backend1',
    'django_openid_auth.auth.Backend2',
    )

例如,您定义了以下两个后端。Django首先会进入第一个后端,您只需要在该后端中放置一些逻辑,以便如果与该后端无关,则将其转发到另一个后端或返回没有任何结果。如果没有结果,Django将自动将请求从第一个后端转移到第二个后端,如果有第三个后端也是如此。 我花了很多时间研究这个问题,发现它并不那么复杂。

我不明白为什么你发布了一个与我的回答几乎相同的答案,而且还早了两周... :( - janos
其实伙计,我没有完全理解你想说什么,所以我按照你的答案做了一些自己的魔法,然后就完成了。你的答案很好。如果我们把我们两个的答案结合起来,并在底部再加上一个答案,那么这个问题的最佳答案就出来了。祝好运! - Rai Muhammad Ehtisham
3
你本可以在评论区留言,我会进行澄清;-) 我已经澄清了,你认为怎么样?如果你仍然认为需要修改,请告诉我。 - janos
现在完美了。这是问题的最佳答案。 - Rai Muhammad Ehtisham

1
使用多个身份验证后端非常容易,您只需要将以下代码添加到settings.py中。
AUTHENTICATION_BACKENDS = (
    'social_core.backends.open_id.OpenIdAuth',
    'social_core.backends.google.GoogleOpenId',
    'social_core.backends.google.GoogleOAuth2',
    'social_core.backends.google.GoogleOAuth',
    'social_core.backends.facebook.FacebookOAuth2',
    'django.contrib.auth.backends.ModelBackend',
)

在views.py文件中的signup视图函数中添加一个login参数,如下所示,这可能会在注册页面上创建问题: login(request, user, backend='django.contrib.auth.backends.ModelBackend')
def signup_view(request):
    if request.method=='POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            user=form.save()
            login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            return redirect('home')

0

对代码进行了一些安全性和重组,因为提供的解决方案并不完全符合要求。

我对之前的版本进行了修改:https://dev59.com/2GQn5IYBdhLWcg3wJ0QO#17078818,并加入了@M.Void的评论:

这是位于api/backend.py的身份验证后端。

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.core.validators import validate_email

user_model = get_user_model()


class EmailOrUsernameModelBackend(ModelBackend):
    """EmailOrUsernameModelBackend - UsernameOrEmail custom authentication backend 
    with email or username validation on same field

    provides case insensitive validation of username and email

    BEWARE - if you allow users to register two usernames in differren cases like: Alex and alex - there would be error.

    still uses ModelBackend so provides permissions and is_active validation
    """

    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(user_model.USERNAME_FIELD)
        if username is None or password is None:
            return
        try:
            validate_email(username)
        except ValidationError as e:
            kwargs = {'username__iexact': username}  # remove __iexact to make it case sensitive
        else:
            kwargs = {'email__iexact': username}  # remove __iexact to make it case sensitive
        try:
            user = user_model.objects.get(**kwargs)
        except user_model.DoesNotExist:
            return None
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user

    def get_user(self, user_id):
        try:
            return user_model.objects.get(pk=user_id)
        except user_model.DoesNotExist:
            return None

当然,将其添加到您的身份验证后端中:

AUTHENTICATION_BACKENDS = (
    'api.backend.EmailOrUsernameModelBackend',
    'django.contrib.auth.backends.ModelBackend',
)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接