来自外部源的 Django 用户和身份验证

Posted

技术标签:

【中文标题】来自外部源的 Django 用户和身份验证【英文标题】:Django users and authentication from external source 【发布时间】:2010-11-06 15:04:28 【问题描述】:

我有一个 Django 应用程序,它完全从外部源(通过 HTTP 查询)获取数据。也就是说,我没有本地数据库的选项。会话数据存储在缓存中(在我的开发服务器上,我使用 SQLite 数据库,所以这不是错误源)。我正在使用最前沿的 Django 1.1svn。

输入问题:我想为用户使用Django自带的认证系统。

编写我自己的身份验证后端似乎很简单,但总是在你有一个本地数据库来保存用户的条件下。如果没有数据库,我的主要问题是持久性。

我尝试了以下方法(假设 datasource.get() 是一个返回某种 dict 的函数):

class ModelBackend (object):
    """Login backend."""

    def authenticate (self, username=None, password=None):
        """Check, if a given user/password combination is valid"""

        data = datasource.get ('login', username, password)
        if data and data['ok']:
            return MyUser (username=username)
        else:
            raise TypeError
            return None

    def get_user (self, username):
        """get data about a specific user"""

        try:
          data = datasource.get ('userdata', username)
          if data and data['ok']:
              return data.user
        except:
            pass
        return None


class MyUser (User):
    """Django user who isn't saved in DB"""

    def save (self):
        return None

但是 MyUser 上故意缺少的 save() 方法似乎破坏了登录的会话存储。

如果没有本地数据库,MyUser 应该如何?

【问题讨论】:

我刚刚发现 docs.djangoproject.com/en/dev/howto/auth-remote-user> 似乎在做我想做的事。如果我评估过它,我会发布一个答案(不要气馁添加你自己的;-))。 链接后面有一个不好的'>'...该死的。 【参考方案1】:

好吧,这比我想象的要复杂得多。首先,从http://docs.djangoproject.com/en/dev/howto/auth-remote-user/ 开始,但您需要使用自己的后端和用户对其进行扩展。

from django.contrib.auth.backends import RemoteUserBackend

class MyRemoteUserBackend (RemoteUserBackend):
    # Create a User object if not already in the database?
    create_unknown_user = False

    def get_user (self, user_id):
        user = somehow_create_an_instance_of (MyUser, user_id)
        return user

    def authenticate (self, **credentials):
        check_credentials ()
        user = somehow_create_an_instance_of (MyUser, credentials)
        return user

那么用户:

from django.contrib.auth.models import User

class MyUser (User):

    def save (self):
        """saving to DB disabled"""
        pass

    objects = None # we cannot really use this w/o local DB

    username = ""  # and all the other properties likewise.
                   # They're defined as model.CharField or similar,
                   # and we can't allow that

    def get_group_permissions (self):
        """If you don't make your own permissions module,
           the default also will use the DB. Throw it away"""
        return [] # likewise with the other permission defs

    def get_and_delete_messages (self):
        """Messages are stored in the DB. Darn!"""
        return []

呸! Django 真的 不适合在没有数据库的情况下使用...

【讨论】:

您必须在设置文件中进行哪些更改?我正在尝试这样做,就好像它完全忽略了我的远程后端。 你在AUTHENTICATION_BACKENDS = ( 'myapp.MyappUserBackend', )设置了什么? 是的。我想通了,我需要扩展远程身份验证中间件,因为我传递的凭据与默认凭据不同。【参考方案2】:

除了覆盖save 方法之外,您还可以断开调用它的信号。这就是我在一些对用户数据库具有只读访问权限的应用程序中所做的。

# models.py (for instance)
from django.contrib.auth.models import update_last_login, user_logged_in
user_logged_in.disconnect(update_last_login)

【讨论】:

我正在使用 Django 1.6 和 OP + 这节省了我的时间!谢谢!【参考方案3】:

grepping 源码显示,user.save() 实际上被调用的唯一地方(除了用户创建和密码管理代码,你根本不需要使用)是django.contrib.auth.login(),更新@ 987654324@值。

# TODO: It would be nice to support different login methods, like signed cookies.
user.last_login = datetime.datetime.now()
user.save()

如果您不希望用户数据保留在 DB 中,请尝试添加虚拟 save() 方法。如果我是对的,它应该可以工作。

def save(self, *args, **kwargs):
    pass

当然,因为您根本没有持久性,所以您应该考虑缓存datasource.get 结果,否则在最坏的情况下,您可能会在每次登录用户点击时一次又一次地查询数据。

【讨论】:

以上是关于来自外部源的 Django 用户和身份验证的主要内容,如果未能解决你的问题,请参考以下文章

维护用户会话而无需将用户保存在 django 身份验证系统中

NTLM 和自动匿名身份验证 IIS

来自 Facebook Messenger 机器人对话的 API 身份验证

如何检查该用户是不是已通过来自美味派的身份验证?

带有 JWT 身份验证实现的 Django GraphQL API 仍然允许来自 Postman 的未经身份验证的请求获取数据。我该如何解决?

如何检查来自另一个 keycloak 实例 B 的身份验证 keycloak 实例 A 用户?