【问题标题】:add user_id attribute in AuthenticationMiddleware | Django在 AuthenticationMiddleware 中添加 user_id 属性 |姜戈
【发布时间】:2020-10-29 10:01:51
【问题描述】:

我有以下关于 Django 身份验证中间件的问题:

class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        assert hasattr(request, 'session'), (
            "The Django authentication middleware requires session middleware "
            "to be installed. Edit your MIDDLEWARE setting to insert "
            "'django.contrib.sessions.middleware.SessionMiddleware' before "
            "'django.contrib.auth.middleware.AuthenticationMiddleware'."
        )
        request.user = SimpleLazyObject(lambda: get_user(request))

正如您在此处看到的,中间件从后端调用 get_user 方法(在我的例子中为 simple_jwt)并将此方法放入 SimpleLazyObject 以便稍后进行评估。

def get_user(self, validated_token):
    """
    Attempts to find and return a user using the given validated token.
    """
    try:
        user_id = validated_token[api_settings.USER_ID_CLAIM]
    except KeyError:
        raise InvalidToken(_('Token contained no recognizable user identification'))

    try:
        user = User.objects.get(**{api_settings.USER_ID_FIELD: user_id})
    except User.DoesNotExist:
        raise AuthenticationFailed(_('User not found'), code='user_not_found')

    if not user.is_active:
        raise AuthenticationFailed(_('User is inactive'), code='user_inactive')

    return user

我想做的是保留request.user = SimpleLazyObject(lambda: get_user(request)),以便为使用它的应用程序提供用户实例,但对于我的自定义应用程序,我想添加类似的东西

伪代码

request.user_id = user_id from  user (user_id = validated_token[api_settings.USER_ID_CLAIM])

为了不查询数据库对用户对象的每个请求,以防我只需要user_id,我已经直接在后端的get_user 方法中。

问题 – 如何将 user_idget_user() 传递到 AuthenticationMiddleware.process_request() 并将 request.user_id 属性设置为请求而不评估 SimpleLazyObject

奇怪的是,我无法为 class JWTAuthentication(authentication.BaseAuthentication): 中的请求分配属性,其中 get_user() 属于

谢谢。

Internal Server Error: /auth/users/me/
Traceback (most recent call last):
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\sync.py", line 330, in thread_handler
    raise exc_info[1]
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\core\handlers\exception.py", line 38, in inner
    response = await get_response(request)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\utils\deprecation.py", line 126, in __acall__
    response = await sync_to_async(
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\sync.py", line 296, in __call__
    ret = await asyncio.wait_for(future, timeout=None)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\asyncio\tasks.py", line 440, in wait_for
    return await fut
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\current_thread_executor.py", line 23, in run
    result = self.fn(*self.args, **self.kwargs)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\sync.py", line 334, in thread_handler
    return func(*args, **kwargs)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\contrib\auth\middleware.py", line 26, in process_request
    request.user_id = _get_user_session_key(request)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\contrib\auth\__init__.py", line 58, in _get_user_session_key
    return get_user_model()._meta.pk.to_python(request.session[SESSION_KEY])
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\contrib\sessions\backends\base.py", line 65, in __getitem__
    return self._session[key]
KeyError: '_auth_user_id'

【问题讨论】:

    标签: django django-middleware django-rest-framework-simplejwt


    【解决方案1】:

    您已经拥有可用的用户 ID。它是从 auth.get_user() 中的会话解码而来的,您可以将其复制到您自己的中间件:

    from django.contrib.auth import _get_user_session_key
    
    request.user_id = _get_user_session_key(request)
    

    这是一个 Django 私有 API,不知道他们为什么将其保密。但你也可以只复制它实现的一个衬里:

    request.user_id = get_user_model()._meta.pk.to_python(
        request.session[SESSION_KEY]
    )
    

    【讨论】:

    • 感谢您的回答。在第一种情况下,它会引发异常(主要问题块中的回溯),在第二种情况下,没有可用的 SESSION_KEY 或“SESSION_KEY”键。此外,我使用 JWT 后端,因此它可能是任何 SESSION_KEY
    • 如果你不使用会话身份验证,那么这个中间件什么也不做,你需要自己动手,或者如果你的 JWT 身份验证可用,请查看他们设置 request.user 的位置。
    • 这就是答案。出于某种原因,我确信在 JWT auth 的情况下中间件与它有关。但事实上并非如此。感谢您的回答
    猜你喜欢
    • 2020-08-17
    • 2014-09-20
    • 2019-08-03
    • 1970-01-01
    • 2021-03-10
    • 1970-01-01
    • 2021-03-14
    • 2013-03-29
    • 1970-01-01
    相关资源
    最近更新 更多