Платформа Django Rest — с использованием аутентификации сеанса и токена

#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 случая:

  1. Если он может аутентифицировать запрос с помощью текущего класса, устанавливается DRF request.user . С этого момента этот запрос аутентифицируется.
  2. Если учетные данные для аутентификации отсутствуют, DRF пропускает этот класс
  3. Если учетные данные для аутентификации присутствуют, но недействительны, например, недопустимый токен 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 в DRF DEFAULT_AUTHENTICATION_CLASSES , теперь он работает нормально.