I am trying to get this working but don't know if this is possible. It should be doing it like this.
I developed a web app using Django
+ Rest-Framework
+ jQuery
, and I want to have an external application to consume the same REST
API, using JWT Tokens
for authentication.
My current config is like this.
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)
The tricky part is that when I use:
permission_classes = (IsAuthenticated,)
I can perform ajax
calls from an external application (using a valid JWT
token), but jQuery
calls from within the app (with an authenticated user) fail with:
{"detail":"Authentication credentials were not provided."}
And on the other hand, if I use autentication_classes
instead of permission_classes
:
authentication_classes = (SessionAuthentication, BasicAuthentication)
I can perform ajax calls from within the web app using jQuery
, but external calls fail with the same 403
error.
I tried using both like this:
class ListFileView(APIView):
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
def get(self, request, *args, **kwargs):
...
but the external calls are also rejected.
Is it possible to have these two types of Auth
working together in the same class
view, or should I separate into two endpoints?
EDIT
Example calls from within the app with 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>
And externally via VBA
code:
Set web = CreateObject("WinHttp.WinHttpRequest.5.1")
web.Open "GET", "/api/list/", False
web.SetRequestHeader "Authorization", "Bearer <JWT_TOKEN_HERE>"
web.Send
And these are all provided by drf(django rest framework) and other than these like oauth, oauth2 based authentication are provided by the efforts of the community with help of other python packages. And they can be easily used in the production environment.
After logging in, the server validates the credentials. If valid, it generates a session, stores it, and then sends the session ID back to the browser. The browser stores the session ID as a cookie, which gets sent anytime a request is made to the server. Session-based auth is stateful.
Token authentication refers to exchanging username and password for a token that will be used in all subsequent requests so to identify the user on the server side. This article revolves about implementing token authentication using Django REST Framework to make an API.
I couldn't work out exactly what is going on in your case, because the behavior in the 3 cases you shared does not seem to be consistent, but going to explain simply how authentication and authorization is determined in DRF, this might help you figure the issue out.
You should be able to use two authentication classes with no problems. With DRF, authentication works like this:
At each request, DRF goes over the provided authentication classes, in the order they are defined. For each class, there are 3 cases:
request.user
. From this point on, this request is authenticated.Authorization
header, DRF raises an exception and returns a 403 response.DRF views normally use the DEFAULT_AUTHENTICATION_CLASSES
variable defined in the settings file, but if you provide them in a view, settings are overridden.
Authorization comes into play when you add permission_classes
to your views. permission_classes
control access to your views, so when you add IsAuthenticated
to a view's permission classes, DRF rejects the request with a 403 response if you try to access that view without an authenticated user.
So in your initial case, your internal AJAX request failing in this case suggests that there is no authenticated user data in your request session. I do not know what could be causing this. Perhaps you do not update request session in your login view (Django's login method should do this automatically).
In your second case, you remove permission_classes
from the view, so the view will serve the request regardless if there is an authenticated user in the request or not. So it is expected that your internal AJAX request succeeds here, but I do not know why your external request fails in this case.
In your third case, from the point of your internal AJAX request, the scenario seems to be the same as the first case, so I do not know why your internal AJAX request succeeds in this case but not in the first case. The external request failing here is expected because you added the IsAuthenticated
permission class to the view, but did not include JWTAuthentication
in the authentication_classes, so your request can not be authenticated with your JWT token here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With