Django Rest Framework - использование аутентификации сессии и токена - PullRequest
0 голосов
/ 06 апреля 2019

Я пытаюсь заставить это работать, но не знаю, возможно ли это.Это должно быть сделано так.

Я разработал веб-приложение, используя Django + Rest-Framework + jQuery, и я хочу, чтобы внешнее приложение использовало тот же API REST, используя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 или я должен разделитьe на две конечные точки?

РЕДАКТИРОВАТЬ

Пример вызовов из приложения с помощью 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 Ответ

2 голосов
/ 06 апреля 2019

Я не мог точно определить, что происходит в вашем случае, потому что поведение в трех случаях, которыми вы поделились, кажется непоследовательным, но я просто объясню, как в DRF определяются аутентификация и авторизация, это можетпоможет вам разобраться в проблеме.

Вы сможете использовать два класса аутентификации без проблем.С DRF аутентификация работает следующим образом:

При каждом запросе DRF перебирает предоставленные классы аутентификации в порядке их определения.Для каждого класса есть 3 случая:

  1. Если он может аутентифицировать запрос с текущим классом, DRF устанавливает request.user.С этого момента этот запрос аутентифицируется.
  2. Если учетные данные для проверки подлинности отсутствуют, DRF пропускает этот класс
  3. Если учетные данные для проверки подлинности присутствуют, но недействительны, например недопустимый токен JWT в заголовке авторизации, DRF вызывает исключение и возвращает ответ 403.

Представления DRF обычно используют authentication_classes , определенные в файле настроек, но если вы предоставите их в виде, настройки будут переопределены.

Авторизация вступает в игру, когда вы добавляете license_classes к своим представлениям.license_classes управляют доступом к вашим представлениям, поэтому при добавлении IsAuthenticated к классам разрешений представления DRF отклоняет запрос с ответом 403, если вы пытаетесь получить доступ к этому представлению без аутентифицированного пользователя.

Таким образом, в вашем первоначальном случае ваш внутренний ajax-запрос в этом случае терпит неудачу и предполагает, что в вашем сеансе запроса нет аутентифицированных пользовательских данных.Я не знаю, что может быть причиной этого, может быть, вы не обновляете сеанс запроса в представлении входа в систему (метод входа в django должен делать это автоматически).

Во втором случае вы удаляете allow_classes из представления, поэтому представление будет обслуживать запрос независимо от того, есть ли в запросе аутентифицированный пользователь или нет.Таким образом, ожидается, что ваш внутренний запрос ajax завершится успешно, но я не знаю, почему ваш внешний запрос не выполняется в этом случае.

В вашем третьем случае, с точки зрения вашего внутреннего запроса ajax, сценарий выглядит так:так же, как и в первом случае, поэтому я не знаю, почему ваш внутренний запрос ajax успешно выполняется в этом случае, но не в первом.Здесь ожидается сбой внешнего запроса, потому что вы добавили в представление класс разрешений IsAuthenticated , но не включили JWTAuthentication в authentication_classes, поэтому ваш запрос не может быть аутентифицирован с помощью вашего токена JWT здесь.

...