如何添加身份验证中间件 JWT django?

Posted

技术标签:

【中文标题】如何添加身份验证中间件 JWT django?【英文标题】:How add Authenticate Middleware JWT django? 【发布时间】:2017-12-29 05:18:41 【问题描述】:

我正在尝试创建一个中间件来使用 JWT 进行身份验证,但在视图中 request.user 始终是 AnonymUser。

当我验证中间件通过用户模型更改 request.user 时,确实如此,但在到达视图时,由于某种原因 request.user 始终是匿名用户

我正在使用 Django 1.11

# coding=utf-8
from django.utils.functional import SimpleLazyObject
from django.utils.deprecation import MiddlewareMixin
from django.contrib.auth.models import AnonymousUser, User
from django.conf import settings
from django.contrib.auth.middleware import get_user
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
import jwt
import json


class JWTAuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        request.user = SimpleLazyObject(lambda: self.__class__.get_jwt_user(request))

    @staticmethod
    def get_jwt_user(request):
        user_jwt = get_user(request)
        if user_jwt.is_authenticated():
            return user_jwt
        token = request.META.get('HTTP_AUTHORIZATION', None)
        user_jwt = None
        if token is not None:
            try:
                user_jwt = jwt.decode(
                    token,
                    settings.SECRET_KEY,
                    algorithms=['HS256']
                )
                user_jwt = User.objects.get(
                    id=user_jwt['user_id']
                )
            except Exception as e:
                user_jwt = AnonymousUser
        return user_jwt





MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
     'django.middleware.security.SecurityMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
     'user.middlewares.JWTAuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

【问题讨论】:

MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware' , 'django.middleware.csrf.CsrfViewMiddleware', 'user.middlewares.JWTAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] 【参考方案1】:

我试图复制您的错误,但就我而言,它运行良好,我认为您的问题的根本原因是异常处理方法。 jwt.decode 可以引发多种类型的异常,包括DecodeErrorExpiredSignatureErrorInvalidKeyError 等等,甚至从 jwt.decode 检索到的 dict 也不能​​有 'user_id' 键。

这是一个完整的工作代码

# coding=utf-8
import jwt
import traceback

from django.utils.functional import SimpleLazyObject
from django.utils.deprecation import MiddlewareMixin
from django.contrib.auth.models import AnonymousUser, User
from django.conf import LazySettings
from django.contrib.auth.middleware import get_user

settings = LazySettings()


class JWTAuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        request.user = SimpleLazyObject(lambda: self.__class__.get_jwt_user(request))

    @staticmethod
    def get_jwt_user(request):

        user_jwt = get_user(request)
        if user_jwt.is_authenticated():
            return user_jwt
        token = request.META.get('HTTP_AUTHORIZATION', None)

        user_jwt = AnonymousUser()
        if token is not None:
            try:
                user_jwt = jwt.decode(
                    token,
                    settings.WP_JWT_TOKEN,
                )
                user_jwt = User.objects.get(
                    id=user_jwt['data']['user']['id']
                )
            except Exception as e: # NoQA
                traceback.print_exc()
        return user_jwt

还有一些注意事项,使用 LazySettings 代替设置 Check this thread 始终是一个好习惯

这也是我的中间件订单

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'applications.custom_authentication.middleware.JWTAuthenticationMiddleware', # This is my middleware
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

记得把你的自定义中间件放在django.contrib.auth.middleware.AuthenticationMiddleware中间件之后

【讨论】:

不工作,视图中的 request.user 始终是 AnonymousUser。似乎 request.user 被其他中间件/身份验证后端覆盖。 我在下面有另一个自定义中间件,我可以在其中看到正确的 request.user,但是当涉及到视图时,它总是 AnonymousUser 在您的自定义中间件之后有哪些中间件?您的中间件正在覆盖 request.user 对象?【参考方案2】:

试试这个中间件:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'applications.custom_authentication.middleware.JWTAuthenticationMiddleware', # This is my middleware
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

【讨论】:

以上是关于如何添加身份验证中间件 JWT django?的主要内容,如果未能解决你的问题,请参考以下文章

Django JWT 身份验证 - 用户在中间件中是匿名的

如何添加Authenticate Middleware JWT django?

Node.js - JWT、API:如何实现多个 Passport.js 身份验证中间件?

如何在 django rest 框架中验证 jwt 身份验证中的令牌

如何自定义 django jwt graphql 身份验证

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