django - Django REST Framework:为什么添加 IsAuthenticated 权限只会引发 500 内部错误而不是 401 / 403 错误?
问题描述
我最初基于 Django REST 框架的后端 API 在没有实施任何安全措施的情况下工作。
现在我正在实现一个 JWT 令牌身份验证过程,但意识到后端 - Django 方面一直存在的问题是,一旦我将“IsAuthenticated”添加到“ 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated') ”,从 Django 抛出的页面始终是 500 Internal Error,而不是 401/403 Authenticated Error,我可能至少知道如何解决。
因此,我希望有人可以帮助我指出解决问题的方向。
在过去的 5 天里,我一直在尝试实现一个 JWT 令牌、机器对机器验证、零用户帐户,并且纯粹基于令牌授权访问,并且已经整理了大部分前面-通过 Auth0 结束请求访问过程。
我假设的过程基于我从 Auth0 API 中读取的内容:
- 客户端浏览器向 Auth0 令牌认证 API 发送请求
- Auth0 使用 Token 回复
- 客户端浏览器使用回复的令牌作为授权标头发送到后端 API
- 服务器 API 回复结果数据。
我意识到的当前问题是,在第 4 步时,我的服务器一直抛出 500 错误而不是 401/403 错误。
我很不确定我可能在哪里出错了,希望有人可以提供一些帮助来添加代码以帮助抛出 Authenticated-Error 响应。
设置.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,
}
意见.PY
class TestsViewSet(ModelViewSet):
queryset = Job.objects.all()
serializer_class = JobsSerializer
renderer_classes = (JSONRenderer, )
http_method_names = ['get']
设置.py
Django==1.11.21
django-cors-headers==3.0.0
djangorestframework==3.9.4
djangorestframework-jwt==1.11.0
解决方案
我刚刚正式确定了我自己的错误,这显然是一个菜鸟错误,其中错字是主要问题。
我进行了细粒度的调试尝试,并尝试使用“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 + '/'
显然,上面的代码,在“AUTH0_DOMAIN”返回“None”的情况下,仍然允许它顺利工作,直到应用了两个关键代码行:
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
所以,我的解决方案是只要“AUTH0_DOMAIN”中有一个有效的URL通过,整个过程就可以完美运行。
希望这将有助于拯救另一个灵魂,并将他们从我失去的 7 天尝试中拯救出来。干杯!
推荐阅读
- pandas - 获取熊猫数据框中特定列的累积最频繁状态
- vba - 访问记录集为空
- python - OpenCV - 跟踪图像中的文本
- docker - 为什么这个 ASP.NET Core Docker Image 包含这个“额外的”“FROM build AS publish”多阶段构建步骤?
- keras - 自动编码器 Keras 微调
- postgresql - 用于 postgres 数据库备份的 Kubernetes Cron 作业
- javascript - css 属性行为怪异 - 隐藏 html 元素但留下一个大空白元素占用网站中隐藏元素的相同空间
- openlayers - “dispatchervent”在 openlayers 中做了什么?
- u-boot - UBoot 二进制文件结构和偏移量
- python - 8-断开对象的连通性