7

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

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

4

4 回答 4

9

如果存储在 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

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

于 2012-11-15T23:18:19.253 回答
5

我认为正确的做法是结合中间件和Django 身份验证后端

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/

于 2012-11-12T05:13:55.550 回答
0

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

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

于 2012-11-12T00:54:57.320 回答
0

我相信最好使用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_

它给出了函数名称。

于 2017-04-25T14:04:01.223 回答