使用多个数据库进行 Django 身份验证

Posted

技术标签:

【中文标题】使用多个数据库进行 Django 身份验证【英文标题】:Django authentication with multiple databases 【发布时间】:2019-04-23 22:28:39 【问题描述】:

我想为客户创建一个应用程序,其中每个客户都有自己的数据库。因此作为登录信息,他们需要输入三个不同的字段:客户编号、用户名、密码。

用户名和密码应该做正常的身份验证工作,客户编号可以去正确的数据库用户表进行身份验证,我可以通过 using() 函数去其他数据库。

class CustomAuthBackend(ModelBackend):

def authenticate(self, request, username=None, password=None, **kwargs):
    user = CustomUser.objects.using(request.POST['kundennr']).get(username=username)
    if user.check_password(password) and self.user_can_authenticate(user) :
         try:
            user = CustomUser.objects.using(request.POST['kundennr']).get(username=username)
            return user
         except User.DoesNotExist:
            return None

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

身份验证功能可以正常工作,我猜我遇到的问题是 get_user 函数,因为 get_user 函数没有请求,我可以定义它应该调用哪个数据库。因为每次我打电话给% if user.is_authenticated % 它都会转到默认数据库并说用户是匿名的。 我不知道解决这个问题的正确方法是我的解决方案错了吗?

【问题讨论】:

您想要的相当复杂,您的解决方案将无法正常工作。查看this post 或谷歌搜索“django 多租户” 或者看this book 【参考方案1】:

好的,在尝试了一些东西后,我得到了一个我认为适用于第一步的解决方案,但我不知道如果我这样使用它是否存在安全问题或任何其他错误

from app.models import CustomUser
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import login as auth_login
from app.middleware import ThreadLocal

class CustomAuthBackend(ModelBackend):

def authenticate(self, request, username=None, password=None, **kwargs):
    user = CustomUser.objects.using(request.POST['kundennr']).get(username=username)
    if user.check_password(password) and self.user_can_authenticate(user) :
         try:
            user = CustomUser.objects.using(request.POST['kundennr']).get(username=username)
            request.session['kundennr']=request.POST['kundennr']
            return user
         except User.DoesNotExist:
            return None

def get_user(self, user_id):
    try:
        request = ThreadLocal.get_current_request()
        return CustomUser.objects.using(request.session['kundennr']).get(pk=user_id)
    except User.DoesNotExist:
        return None

我将一个 ThreadLocal.py 导入到中间件中,这样我就可以在 get_user 中获取请求对象,当我登录时,我将客户保存到我在 get_user 中调用的会话变量中,那么这个解决方案是否可以接受或存在一些风险?

【讨论】:

这种方法的问题在于,对于您要获取的每个对象(不仅仅是User),您必须使用正确的数据库添加using()。这变得非常难以管理。另请注意,您正在获取authenticate 第一行中的user(没有尝试.. 除外),然后再次获取相同的user 每次获得新客户并使用 Django 注册数据库时,您将如何创建新数据库(这样您就可以真正做到using())? 我使用 mssql 并获得了一个为客户创建新数据库的脚本,因此我需要为我猜想的每个新客户编辑 settings.py,而且我必须一直使用 using() 但是对我来说,这不是关于它是否是一个不漂亮的解决方案,我只是想知道它是否以这种方式工作,或者是否存在错误或安全风险。是的,我第一次在身份验证中获取用户时需要尝试阻止,但是当我有一个保存客户编号的会话变量时,我每次获得数据库访问权限时都可以复制using(request.session['kundennr']) 您使用的是什么会话后端? Cookie 还是数据库? 那么我想在安全性方面我看不到用户如何操纵会话数据,所以这对我来说似乎是安全的,只要你:只允许通过 https 的请求(对于你的整个site) 并确保在您的设置中将 SESSION_COOKIE_SECURE 设置为 True。

以上是关于使用多个数据库进行 Django 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

如何使 Django REST JWT 身份验证与多个 Web 服务器一起扩展?

JWT 身份验证:使用 UI 令牌对 Graphene/Django (GraphQL) 查询进行身份验证?

在 Django 中使用 JWT 进行身份验证

使用 Django 通道进行会话身份验证

使用 django rest 框架和 django oauth 工具包在单元测试中进行 oAuth 身份验证

使用 Django Rest 框架进行 JWT 令牌身份验证