Django Rest Framework - 使用 Session 和 Token Auth
Django Rest Framework - Using Session and Token Auth
我正在努力让它工作,但不知道这是否可行。应该是这样的。
我使用 Django
+ Rest-Framework
+ jQuery
开发了一个网络应用程序,我希望有一个外部应用程序来使用相同的 REST
API, 使用 JWT Tokens
进行身份验证。
我现在的配置是这样的
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_RENDERER_CLASS': [
'rest_framework.renderers.JSONRenderer',
]
}
SIMPLE_JWT = {
'AUTH_HEADER_TYPES': ('Bearer',),
}
views.py
class ListFileView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request, *args, **kwargs):
user = request.user
if user:
obj = Foo.objects.filter(owner=user)
serializer = FooSerializer(obj, many=True)
data = serializer.data
return Response(data, status=status.HTTP_200_OK)
return Response({'detail': 'You have no access to files.'}, status=status.HTTP_400_BAD_REQUEST)
棘手的部分是当我使用:
permission_classes = (IsAuthenticated,)
我可以执行来自外部应用程序的 ajax
调用(使用有效的 JWT
令牌),但是来自应用程序内部(使用经过身份验证的用户)的 jQuery
调用失败:
{"detail":"Authentication credentials were not provided."}
另一方面,如果我使用 autentication_classes
而不是 permission_classes
:
authentication_classes = (SessionAuthentication, BasicAuthentication)
我可以使用 jQuery
从网络应用程序中执行 ajax 调用,但外部调用失败并出现相同的 403
错误。
我试过像这样使用两者:
class ListFileView(APIView):
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
def get(self, request, *args, **kwargs):
...
但外部调用也被拒绝
是否可以让这两种类型的 Auth
在同一个 class
视图中一起工作,或者我应该分成两个端点?
编辑
来自应用内的示例调用 jQuery
:
<script type="text/javascript">
function loadTblDocs() {
$("#tbl-docs > tbody").empty();
$.ajaxSetup({
headers: { "X-CSRFToken": '{{csrf_token}}' }
});
$.ajax({
type: 'GET',
contentType: "application/json; charset=utf-8",
url: "/api/list/",
dataType: "json",
success: function (data) {
console.log(data);
}
});
};
</script>
并在外部通过 VBA
代码:
Set web = CreateObject("WinHttp.WinHttpRequest.5.1")
web.Open "GET", "/api/list/", False
web.SetRequestHeader "Authorization", "Bearer <JWT_TOKEN_HERE>"
web.Send
我无法弄清楚你的情况到底是怎么回事,因为你分享的3个案例中的行为似乎并不一致,但将简单解释一下DRF中如何确定身份验证和授权,这可能会帮助您解决问题。
您应该可以毫无问题地使用两个身份验证 classes。使用 DRF,身份验证工作如下:
在每次请求时,DRF 都会按照所定义的顺序检查提供的身份验证 classes。对于每个class,有3种情况:
- 如果它可以用当前 class 验证请求,DRF 设置
request.user
。从此时起,此请求已通过身份验证。
- 如果不存在身份验证凭据,DRF 会跳过 class
- 如果身份验证凭据存在但无效,例如
Authorization
header 中的无效 JWT 令牌,DRF 会引发异常并 returns 403 响应。
DRF 视图通常使用设置文件中定义的 DEFAULT_AUTHENTICATION_CLASSES
变量,但如果您在视图中提供它们,设置将被覆盖。
当您将 permission_classes
添加到您的视图时,授权开始发挥作用。 permission_classes
控制对您的视图的访问,因此当您将 IsAuthenticated
添加到视图的权限 classes 时,如果您尝试在没有经过身份验证的用户的情况下访问该视图,DRF 会拒绝该请求并返回 403 响应.
因此,在您的初始情况下,您的内部 AJAX 请求在这种情况下失败表明您的请求 session 中没有经过身份验证的用户数据。我不知道是什么原因造成的。也许您没有在登录视图中更新请求 session(Django 的登录方法应该自动执行此操作)。
在第二种情况下,您从视图中删除了 permission_classes
,因此无论请求中是否存在经过身份验证的用户,视图都会为请求提供服务。所以这里应该是你内部的AJAX请求成功了,但是我不知道为什么你的外部请求在这种情况下会失败。
你的第三种情况,从你的内部AJAX请求来看,场景好像和第一种一样,不知道你的内部AJAX请求为什么成功在这种情况下,但不是在第一种情况下。此处外部请求失败是预料之中的,因为你在视图中添加了IsAuthenticated
权限class,但没有在authentication_classes中包含JWTAuthentication
,所以你的请求无法通过身份验证在此处使用您的 JWT 令牌。
我正在努力让它工作,但不知道这是否可行。应该是这样的。
我使用 Django
+ Rest-Framework
+ jQuery
开发了一个网络应用程序,我希望有一个外部应用程序来使用相同的 REST
API, 使用 JWT Tokens
进行身份验证。
我现在的配置是这样的
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_RENDERER_CLASS': [
'rest_framework.renderers.JSONRenderer',
]
}
SIMPLE_JWT = {
'AUTH_HEADER_TYPES': ('Bearer',),
}
views.py
class ListFileView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request, *args, **kwargs):
user = request.user
if user:
obj = Foo.objects.filter(owner=user)
serializer = FooSerializer(obj, many=True)
data = serializer.data
return Response(data, status=status.HTTP_200_OK)
return Response({'detail': 'You have no access to files.'}, status=status.HTTP_400_BAD_REQUEST)
棘手的部分是当我使用:
permission_classes = (IsAuthenticated,)
我可以执行来自外部应用程序的 ajax
调用(使用有效的 JWT
令牌),但是来自应用程序内部(使用经过身份验证的用户)的 jQuery
调用失败:
{"detail":"Authentication credentials were not provided."}
另一方面,如果我使用 autentication_classes
而不是 permission_classes
:
authentication_classes = (SessionAuthentication, BasicAuthentication)
我可以使用 jQuery
从网络应用程序中执行 ajax 调用,但外部调用失败并出现相同的 403
错误。
我试过像这样使用两者:
class ListFileView(APIView):
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
def get(self, request, *args, **kwargs):
...
但外部调用也被拒绝
是否可以让这两种类型的 Auth
在同一个 class
视图中一起工作,或者我应该分成两个端点?
编辑
来自应用内的示例调用 jQuery
:
<script type="text/javascript">
function loadTblDocs() {
$("#tbl-docs > tbody").empty();
$.ajaxSetup({
headers: { "X-CSRFToken": '{{csrf_token}}' }
});
$.ajax({
type: 'GET',
contentType: "application/json; charset=utf-8",
url: "/api/list/",
dataType: "json",
success: function (data) {
console.log(data);
}
});
};
</script>
并在外部通过 VBA
代码:
Set web = CreateObject("WinHttp.WinHttpRequest.5.1")
web.Open "GET", "/api/list/", False
web.SetRequestHeader "Authorization", "Bearer <JWT_TOKEN_HERE>"
web.Send
我无法弄清楚你的情况到底是怎么回事,因为你分享的3个案例中的行为似乎并不一致,但将简单解释一下DRF中如何确定身份验证和授权,这可能会帮助您解决问题。
您应该可以毫无问题地使用两个身份验证 classes。使用 DRF,身份验证工作如下:
在每次请求时,DRF 都会按照所定义的顺序检查提供的身份验证 classes。对于每个class,有3种情况:
- 如果它可以用当前 class 验证请求,DRF 设置
request.user
。从此时起,此请求已通过身份验证。 - 如果不存在身份验证凭据,DRF 会跳过 class
- 如果身份验证凭据存在但无效,例如
Authorization
header 中的无效 JWT 令牌,DRF 会引发异常并 returns 403 响应。
DRF 视图通常使用设置文件中定义的 DEFAULT_AUTHENTICATION_CLASSES
变量,但如果您在视图中提供它们,设置将被覆盖。
当您将 permission_classes
添加到您的视图时,授权开始发挥作用。 permission_classes
控制对您的视图的访问,因此当您将 IsAuthenticated
添加到视图的权限 classes 时,如果您尝试在没有经过身份验证的用户的情况下访问该视图,DRF 会拒绝该请求并返回 403 响应.
因此,在您的初始情况下,您的内部 AJAX 请求在这种情况下失败表明您的请求 session 中没有经过身份验证的用户数据。我不知道是什么原因造成的。也许您没有在登录视图中更新请求 session(Django 的登录方法应该自动执行此操作)。
在第二种情况下,您从视图中删除了 permission_classes
,因此无论请求中是否存在经过身份验证的用户,视图都会为请求提供服务。所以这里应该是你内部的AJAX请求成功了,但是我不知道为什么你的外部请求在这种情况下会失败。
你的第三种情况,从你的内部AJAX请求来看,场景好像和第一种一样,不知道你的内部AJAX请求为什么成功在这种情况下,但不是在第一种情况下。此处外部请求失败是预料之中的,因为你在视图中添加了IsAuthenticated
权限class,但没有在authentication_classes中包含JWTAuthentication
,所以你的请求无法通过身份验证在此处使用您的 JWT 令牌。