#python #django #django-rest-framework #django-rest-framework-simplejwt
#python #django #django-rest-framework #django-rest-framework-simplejwt
Вопрос:
Я пытаюсь заставить это работать, но не знаю, возможно ли это. Это должно быть сделано вот так.
Я разработал веб-приложение, используя 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)
Я могу выполнять вызовы ajax из веб-приложения с помощью jQuery
, но внешние вызовы завершаются с той же 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
Комментарии:
1. можете ли вы показать, как вы вызываете API?
2. @JPG с помощью
jQuery
или извне?3. В @JPG добавлены оба
jQuery
иVBA
примеры вызовов.4. можете ли вы также опубликовать свой вид входа? используете ли вы там метод входа в систему Django?
5. Да, я использую стандартный логин django
Ответ №1:
Я не смог точно определить, что происходит в вашем случае, потому что поведение в 3 случаях, которыми вы поделились, не кажется последовательным, но собираюсь просто объяснить, как аутентификация и авторизация определяются в DRF, это может помочь вам разобраться в проблеме.
Вы должны иметь возможность использовать два класса аутентификации без проблем. С DRF аутентификация работает следующим образом:
При каждом запросе DRF перебирает предоставленные классы аутентификации в том порядке, в котором они определены. Для каждого класса существует 3 случая:
- Если он может аутентифицировать запрос с помощью текущего класса, устанавливается DRF
request.user
. С этого момента этот запрос аутентифицируется. - Если учетные данные для аутентификации отсутствуют, DRF пропускает этот класс
- Если учетные данные для аутентификации присутствуют, но недействительны, например, недопустимый токен JWT в
Authorization
заголовке, DRF вызывает исключение и возвращает ответ 403.
Представления DRF обычно используют DEFAULT_AUTHENTICATION_CLASSES
переменную, определенную в файле настроек, но если вы предоставляете их в представлении, настройки переопределяются.
Авторизация вступает в игру, когда вы добавляете permission_classes
в свои представления. permission_classes
контролируйте доступ к своим представлениям, поэтому, когда вы добавляете IsAuthenticated
к классам разрешений представления, DRF отклоняет запрос с ответом 403, если вы пытаетесь получить доступ к этому представлению без аутентифицированного пользователя.
Итак, в вашем первоначальном случае сбой вашего внутреннего запроса AJAX в этом случае предполагает, что в вашем сеансе запроса нет аутентифицированных пользовательских данных. Я не знаю, что может быть причиной этого. Возможно, вы не обновляете сеанс запроса в своем представлении входа (метод входа в систему Django должен делать это автоматически).
Во втором случае вы удаляете permission_classes
из представления, поэтому представление будет обслуживать запрос независимо от того, есть ли в запросе аутентифицированный пользователь или нет. Таким образом, ожидается, что ваш внутренний запрос AJAX здесь будет выполнен успешно, но я не знаю, почему ваш внешний запрос завершается неудачей в этом случае.
В вашем третьем случае, с точки зрения вашего внутреннего запроса AJAX, сценарий, похоже, такой же, как и в первом случае, поэтому я не знаю, почему ваш внутренний запрос AJAX выполняется успешно в этом случае, но не в первом случае. Ошибка внешнего запроса здесь ожидается, потому что вы добавили IsAuthenticated
класс разрешений в представление, но не включили JWTAuthentication
в authentication_classes, поэтому ваш запрос не может быть аутентифицирован с помощью вашего токена JWT здесь.
Комментарии:
1. Вы правы, и спасибо вам за это подробное объяснение. Оказывается, я на самом деле использовал неправильный
settings.py
файл в рабочей среде, в котором отсутствовала эта строкаrest_framework.authentication.SessionAuthentication
в DRFDEFAULT_AUTHENTICATION_CLASSES
, теперь он работает нормально.