Django 5 для начинающих

Прогресс по курсу:  9/1004

8.7 Права доступа и токены в DRF
4 из 4 шагов пройдено

Безопасность является важной частью любого веб-сайта, но в случае с веб-интерфейсами она важна вдвойне.

В настоящее время API нашего блога предоставляет полный доступ любому пользователю. Нет никаких ограничений; любой пользователь может делать всё, что угодно, что крайне опасно. Например, анонимный пользователь может создавать, читать, обновлять или удалять любую запись в блоге. Даже ту, которую он не создавал! Очевидно, что мы этого не хотим.

Django REST Framework поставляется с несколькими готовыми настройками разрешений, которые мы можем использовать для защиты нашего API. Они могут быть применены на уровне проекта, на уровне представления или на уровне отдельной модели.

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

Разрешения на уровне проекта

Django REST Framework имеет множество конфигураций, которые разнесены по именам внутри одного параметра Django под названием REST_FRAMEWORK. Мы уже сделали одну из них, AllowAny, явной в файле mysite/settings.py:

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.AllowAny",
    ],
......
}

API Reference

AllowAny

Класс разрешения AllowAny разрешает неограниченный доступ, независимо от того, был ли запрос аутентифицирован или неаутентифицирован. Это разрешение не является строго обязательным, поскольку вы можете достичь того же результата, используя пустой список или кортеж для установки разрешений, но вы можете посчитать полезным указать этот класс, поскольку он делает намерение явным.

IsAuthenticated

Класс разрешения IsAuthenticated будет запрещать разрешение любому пользователю, не прошедшему аутентификацию, и разрешать в противном случае. Это разрешение подходит, если вы хотите, чтобы ваш API был доступен только зарегистрированным пользователям.

IsAdminUser

Класс разрешения IsAdminUser запрещает разрешение любому пользователю, если только user.is_staff не является True, в этом случае разрешение будет разрешено. Это разрешение подходит, если вы хотите, чтобы ваш API был доступен только подгруппе доверенных администраторов.

IsAuthenticatedOrReadOnly

Параметр IsAuthenticatedOrReadOnly позволит аутентифицированным пользователям выполнять любые запросы. Запросы для неаутентифицированных пользователей будут разрешены, только если метод запроса является одним из "безопасных" методов: GET, HEAD или OPTIONS. Это разрешение подходит, если вы хотите, чтобы ваш API разрешал разрешения на чтение анонимным пользователям и разрешал разрешения на запись только аутентифицированным пользователям.

Давайте переключимся на IsAuthenticated, чтобы только аутентифицированные, или вошедшие в систему, пользователи могли просматривать API. Обновите файл mysite/settings.py следующим образом:

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticated",
    ],
.....
...
}

Давайте перейдем по адресу блога - http://127.0.0.1:8000 и выйдем из аккаунта. А после чего зайдем по адресу нашего API http://127.0.0.1:8000/api/ и увидим следующее окошко, которое просит нас авторизоваться:

И в случае если мы не будем авторизовываться, мы не сможем получить доступ к нашему сервису REST API.

Иногда бывают конфликты, а именно невозможно выйти из аккаунта в нашем API. В данном случае можно отключить нашу базовую авторизацию в настройках REST_FRAMEWORK:

    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        # 'rest_framework.authentication.BasicAuthentication',

    ),

  • Комментария
Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий

У меня не появляется форма запроса авторизации, сразу получаю 403 страницу. В чем может быть дело?

@Александр_Алтухов, А до замены AllowAny на IsAuthenticated все работало?

@Илья_Перминов, До замены было другое поведение - авторизация не запрашивалась. Работает все штатно, только не запрашивается авторизация.

@Александр_Алтухов, отправьте архив проекта на почту perminoff-ilya@yandex.ru , попытаемся выяснить причину.

@Александр_Алтухов, отправляли ли свой проект? Он мне не пришёл на почту.

@Илья_Перминов, Да, отправил по адресу, который указал Дмитрий.

Отправьте ещё раз, мне ничего не приходило.

@Александр_Алтухов, нашли решение?

@Попов_Станислав, да, спасибо Илье за консультацию и помощь.

@Попов_Станислав, отредактируйте файл настроек таким образом:

    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication' # new
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ),

@Дмитрий_Селезнев, теперь из аккаунта невозможно выйти, а если сменять аккаунт через /account/login, а после выйти из него в /api/, то вместо авторизации автоматически подбивается пользователь, данные которого я ввел в всплывающем модальном окне

@Попов_Станислав, у Ильи проект Александра Алтухова заработал без каких-либо правок, а Александру помогло добавление этой строчки.

@Попов_Станислав, загрузите проект по ссылке https://mega.nz/filerequest/rANtUqzWHQ4, предварительно выполнив команду:

pip freeze > requirements.txt

Попытаемся выяснить причину.

Та же проблема 

Определил DEFAULT_AUTHENTICATION_CLASSES, один раз авторизация сработала по адресу .../api, но дальнейшие вход выход пользователя в блоге - не вызывают повторной авторизации для ./api. Т.е. интерфейс api доступен в режиме редактирования.

PS: даже определив logout вьюху, все равно не взлетает 

PSS: выключив BasicAuthentication (по рекомендации в следующем шаге), выход и вход в api стал работать

Изменен Антон Глухенко

@Антон_Глухенко, ага, перенесли в этот шаг этот абзац.

@Попов_Станислав, У меня все прекрасно работает.

Мы можем с вами связаться в телеграмме(@Perminoff_ilya) или дискорде(permin0ff) ? Очень хочется решить эту проблему.

Изменен Илья Перминов

@Дмитрий_Селезнев, у меня тоже аутентификация появляется только с этой строкой

Опечатки

пользователь может делать все, что угодно, что что крайне опасно

чтобы только только автор

не возможно

Изменен Константин Малыхин

@Константин_Малыхин, спасибо, исправил.

Подскажите пожалуйста иначе я запутаюсь при чем тут DEFAULT_AUTHENTICATION_CLASSES и куда это нужно вставлять???
 

Иногда бывают конфликты, а именно невозможно выйти из аккаунта в нашем API. В данном случае можно отключить нашу базовую авторизацию в настройках REST_FRAMEWORK:

    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        # 'rest_framework.authentication.BasicAuthentication',

    ),

я просто сделал 
 

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticated",
    ],
.....
...
}

поначалу у меня были ошибки при выходе но я раз 5 обновил страничку и все ок но при переходе на http://127.0.0.1:8000/api/ нет никакой форма авторизации потому что ее там и не должно быть она по адресу http://127.0.0.1:8000/accounts/login/ или тут что то не то?

 Давайте перейдем по адресу нашего API - http://127.0.0.1:8000 и выйдем из аккаунта. А после чего зайдем по адресу http://127.0.0.1:8000/api/ и увидим следующее окошко, которое просит нас авторизоваться:

Изменен No Name

@No_Name, вот мои настройки у меня все работает выход вход так же если вышел доступа к апи нет,
 

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticated",
    ],
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],  # new
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',  # new
    'PAGE_SIZE': 3   # new
}


у вас тут две одинаковые ссылки переход на апи 

Давайте перейдем по адресу нашего API - http://127.0.0.1:8000 и выйдем из аккаунта. А после чего зайдем по адресу http://127.0.0.1:8000/api/ и увидим следующее окошко, которое просит нас авторизоваться:

при копировании адреса ссылки  API - http://127.0.0.1:8000  вот ссылка http://127.0.0.1:8000/api/ проверьте сами так же при переходе по ссылке http://127.0.0.1:8000/ показывает просто стандартную страничку блога и все нет поля авторизоваться!

@No_Name, ссылку я исправил.

В итоге настройки должны получится такими:

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],

    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',  # new
    'PAGE_SIZE': 5,

    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        # 'rest_framework.authentication.BasicAuthentication',
    ),
}
Изменен Дмитрий Селезнев

@Дмитрий_Селезнев, Спасибо, у меня все тоже самое ничего не поменялось. в плане все работает как раньше, при переходе по ссылке показывает страницу блога главную не вошедшею в аккаунт 

http://127.0.0.1:8000/
Изменен No Name

@No_Name, значит правильно работает, код настроек был ответом на предыдущее сообщение:

Подскажите пожалуйста иначе я запутаюсь при чем тут DEFAULT_AUTHENTICATION_CLASSES и куда это нужно вставлять