Django REST Framework: почему добавление разрешений IsAuthenticated вызывало только внутреннюю ошибку 500 вместо ошибок 401/403?

Мой исходный backend API, основанный на Django REST Framework, работал без каких-либо мер безопасности.

Теперь я реализую процесс аутентификации токена JWT, но понял, что проблема с постоянными ошибками на стороне backend-Django заключалась в том, что после добавления «IsAuthenticated» в «'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated') ", страница, которую выдает Django, постоянно представляет собой внутреннюю ошибку 500, а не ошибку аутентификации 401/403, из которой я, по крайней мере, могу знать, как двигаться дальше в разрешении.

Таким образом, я надеюсь, что кто-то может помочь мне указать направление в решении этой проблемы.


В течение последних 5 дней я пытался реализовать токен JWT, межмашинную проверку, с нулевой учетной записью и исключительно на основе доступа к авторизации токена, и я вроде как разобрал большую часть фронт- завершить процесс запроса доступа через Auth0.

Процесс, который, как я предполагал, работает, основан на том, что я прочитал из Auth0 API:

  1. Клиентский браузер отправляет запрос в API аутентификации токена Auth0
  2. Auth0 отвечает токеном
  3. Клиентский браузер использует ответный токен для отправки в качестве заголовка авторизации в серверный API.
  4. Серверный API отвечает данными результатов.

Текущая проблема, которую я осознал, заключается в том, что на шаге 4 мой сервер продолжал выдавать 500 ошибок вместо ошибок 401/403.

Я совершенно не уверен, где я мог ошибиться, и надеюсь, что кто-то может оказать некоторую помощь в добавлении кода, который поможет генерировать ответ Authenticated-Error.


SETTINGS.PY


import json
from six.moves.urllib import request
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend


INSTALLED_APPS = [

    # Third-Party Apps
    'corsheaders',
    'rest_framework',
    'rest_framework_jwt',

]

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        # GLOBAL SETTINGS SETUP FOR "DEFAULT_PERMISSION_CLASSES"
        'rest_framework.permissions.IsAuthenticated', 
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        # GLOBAL SETTINGS SETUP FOR "DEFAULT_AUTHENTICATION_CLASSES"
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
    'EXCEPTION_HANDLER': (
        # GLOBAL SETTINGS SETUP FOR "EXCEPTION_HANDLER"
        'rest_framework.views.exception_handler',
    ),
}


MIDDLEWARE = [
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.RemoteUserMiddleware',
]



AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'django.contrib.auth.backends.RemoteUserBackend',
]



AUTH0_DOMAIN = os.environ.get('AUTH0_DOMAIN')
API_IDENTIFIER = os.environ.get('API_IDENTIFIER')
PUBLIC_KEY = os.environ.get('PUBLIC_KEY')
JWT_ISSUER = os.environ.get('ISSUER')

# If AUTH0_DOMAIN is defined, load the jwks.json
if AUTH0_DOMAIN:
    jsonurl = request.urlopen('https://' + AUTH0_DOMAIN + '/.well-known/jwks.json')
    jwks = json.loads(jsonurl.read())
    cert = '-----BEGIN CERTIFICATE-----\n' + jwks['keys'][0]['x5c'][0] + '\n-----END CERTIFICATE-----'
    certificate = load_pem_x509_certificate(cert.encode('utf-8'), default_backend())
    PUBLIC_KEY = certificate.public_key()
    JWT_ISSUER = 'https://' + AUTH0_DOMAIN + '/'

# JWT settings
JWT_AUTH = {
    'JWT_PAYLOAD_GET_USERNAME_HANDLER':
        'backend.user.jwt_get_username_from_payload_handler',   # REDIRECT TO "backend.user" INSTEAD OF "auth0authorization.user"
    'JWT_PUBLIC_KEY': PUBLIC_KEY,
    'JWT_ALGORITHM': 'RS256',
    'JWT_AUDIENCE': API_IDENTIFIER,
    'JWT_ISSUER': JWT_ISSUER,
    'JWT_AUTH_HEADER_PREFIX': 'Bearer',

    'JWT_ALLOW_REFRESH': True,
}


VIEWS.PY

class TestsViewSet(ModelViewSet):
    queryset = Job.objects.all()
    serializer_class = JobsSerializer
    renderer_classes = (JSONRenderer, )
    http_method_names = ['get']

SETTINGS.PY

Django==1.11.21
django-cors-headers==3.0.0
djangorestframework==3.9.4
djangorestframework-jwt==1.11.0


person sgrobert    schedule 24.06.2019    source источник
comment
500 - ошибка сервера. Если DEBUG включен, это должно привести к появлению кода ошибки более 500, должно быть какое-то сообщение об ошибке.   -  person Nikita Tonkoskur    schedule 24.06.2019
comment
Привет @bloodwithmilk! Ошибка стандартная: «TypeError at / api / test / 'list' объект не вызывается. Метод запроса: GET URL-адрес запроса: localhost: 8000 / api / test Версия Django: 1.11.21 Тип исключения: TypeError Значение исключения: объект 'list' не вызывается Местоположение исключения: / usr / local / lib / python2.7 / site-packages / rest_framework / views.py в handle_exception, строка 452 Исполняемый файл Python: /usr/local/opt/python@2/bin/python2.7 Версия Python: 2.7.16 ''   -  person sgrobert    schedule 25.06.2019


Ответы (1)


Я только что официально определил свою ошибку, и это была просто ошибка новичка, когда опечатка была главной проблемой.

Я предпринял детальную попытку отладки и попытался использовать «print ()» для проверки потенциальных переменных, которые, как я думал, могут быть причиной проблемы.

В итоге я обнаружил, что основная проблема связана со следующим:

  • РАБОЧИЙ КОД --- AUTH0_DOMAIN = os.environ.get ('JWT_AUTH0_DOMAIN')
  • КОД ОШИБКИ --- AUTH0_DOMAIN = os.environ.get ('AUTH0_DOMAIN')

Я искренне верю, что это ошибка, которую совершат все разработчики, и я на этот раз явно пропущу ошибку опечатки, поскольку код мне кажется логичным.

Я бы посоветовал другим, если вы, как и я, используете файл .env для хранения всех этих переменных, используйте функцию "print ()", например "print (" AUTH0_DOMAIN ----- :% r "% AUTH0_DOMAIN)", чтобы проверить потенциальные области проблемы, которые связаны с результатом вашего кода.

Исходя из своего опыта, я предполагаю, что ошибка 500, выданная в моем случае, была вызвана тем, что сервер просто не может «ответить» на результат, поскольку переменная «AUTH0_DOMAIN» предполагает предоставление URL-адреса. И следующий код, как показано ниже:

AUTH0_DOMAIN = os.environ.get('JWT_AUTH0_DOMAIN')
API_IDENTIFIER = os.environ.get('JWT_API_IDENTIFIER')
PUBLIC_KEY = os.environ.get('PUBLIC_KEY')
JWT_ISSUER = os.environ.get('ISSUER')

if AUTH0_DOMAIN:
    jsonurl = request.urlopen('https://' + AUTH0_DOMAIN + '/.well-known/jwks.json')
    jwks = json.loads(jsonurl.read())
    cert = '-----BEGIN CERTIFICATE-----\n' + jwks['keys'][0]['x5c'][0] + '\n-----END CERTIFICATE-----'
    certificate = load_pem_x509_certificate(cert.encode('utf-8'), default_backend())
    PUBLIC_KEY = certificate.public_key()
    JWT_ISSUER = 'https://' + AUTH0_DOMAIN + '/'

По-видимому, приведенный выше код с «None», возвращенным «AUTH0_DOMAIN», по-прежнему позволял ему работать без сбоев до тех пор, пока не будут применены две ключевые строки кода:

'DEFAULT_PERMISSION_CLASSES': (
       'rest_framework.permissions.IsAuthenticated', 
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),

Итак, мое решение заключается в том, что до тех пор, пока в "AUTH0_DOMAIN" передается действительный URL-адрес, весь процесс будет работать отлично.

Надеюсь, это поможет спасти еще одну душу и избавить ее от 7-дневных попыток, которые я потерял из своих. Ваше здоровье!

person sgrobert    schedule 26.06.2019