Использование внешнего API для аутентификации на основе токенов в Django (DRF) - PullRequest
0 голосов
/ 11 марта 2020

Context

Мой API принимает токен jwt, который я могу передать внешней конечной точке, которая вернет 401, если недействителен / истек срок действия, или информацию о пользователе, если она все еще действительна. На основании этого я либо верну 401, либо отфильтрованные данные, принадлежащие пользователю. Кроме того, POST-запрос должен включать в себя написание того, кому принадлежит этот ресурс, чтобы GET работал. Я попытался сделать это, переопределив методы get_queryset и execute_create.

Мой набор выглядит примерно так:

class ReportViewSet(AuthorizedUserBasedFilteredViewset):
    queryset = Report.objects.all()
    serializer_class = ReportSerializer

    def perform_create(self, serializer):
        try:
            username = self.get_authorized_user()['user']['username']
        except Exception as e:
            return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)
        serializer.save(creatd_by=username)

    def get_queryset(self):
        try:
            username = self.get_authorized_user()['user']['username']
        except Exception as e:
            return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)
        return Report.objects.filter(created_by=username)

Это не работает, потому что get_queryset ожидает набор запросов в качестве ответа.

Вопросы

  1. Как вызвать исключение авторизации в get_queryset? Есть ли какой-то другой метод, который я должен полностью переопределить для аутентификации? Мне все еще нужно передать полученное имя пользователя в get_queryset для успешной аутентификации
  2. Есть ли лучший способ сделать это? Я чувствую, что вызов внешнего API-аутентификации и установка доступа пользователя к методам get_queryset и execute_create в идеале go где-то в другом месте кода. Я посмотрел на RemoteUserAuthenticationBackend, но он все еще включал создание объекта User, но для этого случая использования модель пользователя полностью внешняя

1 Ответ

1 голос
/ 12 марта 2020

Вместо

return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)

используйте эту

raise NotAuthenticated(detail='Token does not exist')

Надеюсь, что над строкой адресован ваш 1-й вопрос.

Для 2-го вопроса. Вы можете расширить TokenAuthentication и затем реализовать метод def authenticate_credentials(self, key):. Не рекомендуется вызывать внешний API для выборки пользователя каждый раз . Скорее вы должны получить токен JTW один раз из внешнего источника, а затем передать токен JWT в заголовке, например Authorization : Bearer cn389ncoiwuencr, для каждого вызова API. Затем вы должны декодировать токен JWT в текущей системе.

from rest_framework.authentication import TokenAuthentication
from django.contrib.auth import get_user_model
class CustomTokenAuthentication(TokenAuthentication):
    keyword = 'Bearer' # token type
    def authenticate_credentials(self, key):
        #decode JWT.
        username = get_username()
        User = get_user_model()
        user = User(username=username)
        return user, key

Наконец, добавьте этот класс в файл settings.py.

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'path.of.CustomTokenAuthentication',
    )
}

Это будет применяться ко всем вашим представлениям. или вы можете применить спецификацию вида c auth class.

class Sample(ViewSet):
    authentication_classes = (CustomTokenAuthentication,)

Теперь вы можете получить доступ к пользователю с помощью request.user в представлениях или наборе. Вот и все.

...