【问题标题】:Override Django authentication with middleware使用中间件覆盖 Django 身份验证
【发布时间】:2012-10-31 11:39:32
【问题描述】:

我有一个 Django 网站和一个 MyBB 论坛,我想在它们之间共享身份验证。我的网站曾经是一个留言板;然后我在 Django 中构建了其他一些部分,MyBB 和 Django 都在同一个域上运行。我建立了一个系统,在注册时(在论坛上),每个用户都会获得两个用户:一个 Django 用户和一个 MyBB 用户。用户使用论坛登录,所以需要Django读取MyBB的cookies并将对应的Django账号设置为登录用户。

我可以用中间件做到这一点吗?该中间件将读取 MyBB 的 cookie(其中包含 MyBB 用户的 id)并将 request.user 设置为相应的 Django 用户。我是 Django 新手,我不确定在中间件中设置request.user(或调用authenticate)是否是个好主意(或者是否有更好的方法)。

【问题讨论】:

    标签: django authentication django-middleware


    【解决方案1】:

    尝试处理request.sessionrequest 对象作为第一个参数出现。有关会话的更多详细信息,请点击此处:https://docs.djangoproject.com/en/dev/topics/http/sessions/

    你绝对可以用中间件做到这一点:更多关于中间件的信息:https://docs.djangoproject.com/en/dev/topics/http/middleware/

    【讨论】:

      【解决方案2】:

      我认为将中间件和Django authentication backend 结合起来是正确的选择。

      您的中间件将调用后端的authenticate(),可能会将用户ID 作为关键字参数。您的身份验证后端将依次调用相应的authenticate() 方法并返回一个用户对象。

      class MiddlewareTracker:
       def process_request(self, request):
          id = request.COOKIES.get('logged_in_id') 
          authenticate(user_id = id)
          return None
      
      class ForumAuthBackend(object):
      
          def authenticate(self, *args, **kwargs):
              id = kwargs.get('user_id')
              return User.objects.get(id = id)
      
          def get_user(self, user_id):
              return User.objects.get(id = user_id)
      

      我也会推荐通过这个https://docs.djangoproject.com/en/1.2/topics/auth/

      【讨论】:

      • 这对我不起作用。 authenticate 调用无效。我已经检查了中间件和身份验证后端的顺序。我还检查了 backed 是否返回了一个有效的 User 对象。
      • 您是否将 AUTHENTICATION_BACKENDS 设置为您的后端?您还可以解释一下身份验证调用无效是什么意思吗?它被调用了吗?
      • 已更改为request.user = authenticate(user_id = id),现在可以使用了。
      • 酷,你能分享你的代码吗?并将问题标记为已回答。是我的答案还是发布您的代码作为您的答案?
      • 几乎相同的代码,我只是用request.user = authenticate(user_id = id)替换了您的authenticate调用。
      【解决方案3】:

      如果存储在您的 MyBB cookie 中的 user_id 代表 Django 数据库中的同一用户,那么您可以使用默认的 Django 后端直接从该 id 获取用户对象。如果这些 ID 不匹配,您需要自定义后端来获取 Django 用户对象。 要从 MyBB cookie 中获取用户 ID 并根据它更新用户,您需要有一个自定义的身份验证中间件。

      中间件

      主要思想是获取用户对象(基于您的身份验证逻辑)并将其分配给 request.user。这是一个示例(未测试)。

      from django.contrib import auth
      
      class MyBBMiddleware:
          def process_request(self, request):
              user_cookie_name = "session_key"
              if user_cookie_name not in request.COOKIES:
                  # log user out if you want
                  return 
              id = request.COOKIES.get(user_cookie_name)
              # this will find the right backend
              user = auth.authenticate(id) 
              request.user = user
              # if you want to persist this user with Django cookie do the following
              #auth.login(request, user)
      

      请记住,每个发送到您的 Django 站点的请求都会调用此函数。为了提高性能,您可以缓存用户和/或做一个惰性对象技巧,EXAMPLE

      后端

      如果您需要编写自己的逻辑来获取用户对象和验证用户,您可以执行以下操作。

      class MyBBCookieBackend(object):
          def authenticate(self, user_id):
              return self.get_user(user_id)
          def get_user(self, user_id):
              # if user_id is not the same in Django and MyBB tables, 
              #  you need some logic to relate them and fetch Django user
              try:
                  #TODO your custom logic
                  user = User.objects.get(id=user_id)
                  return user
              except User.DoesNotExist:
                  return None
      

      您需要在站点设置文件中添加自定义后端和中间件。

      【讨论】:

        【解决方案4】:

        我认为最好使用process_view 而不是process_request,因为进程视图具有以下信息:

        1. 请求
        2. 要调用的函数
        3. 传递的参数

        process_view(request, view_func, view_args, view_kwargs):
            if not request.user.is_authenticated():
                return HttpResponseRedirect(settings.LOGIN_URL)
            return None
        

        这使它更灵活,因为我们也有函数information(view_func)。 因此,我们也可以通过以下方式将其限制为某些功能:

        view_func.__name_
        

        给出函数名称。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-07-16
          • 2011-05-10
          • 2019-05-22
          • 2019-01-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多