Декораторы для проверки прав доступа в Django

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

Наиболее часто используемым декоратором является login_required. Его удобно применять в сочетании с представлением, которое разрешает доступ только тем пользователям, которые прошли процедуру проверки подлинности.

from django.contrib.auth.decorators import login_required

@login_required(login_url='/dashboard/')
def index(request):
    return render(request, 'index.html')

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

Для входа требуется необязательный аргумент login_url. Если пользователь аутентифицирован, функция выполняется. Если нет, происходит перенаправление пользователей на URL, указанный в параметре login_url. Если параметр login_url опустить, то необходимо определить login_url в settings.py.

Но декоратор login_required не проверяет, разрешено ли пользователю авторизовываться на сайте. Можно использовать user_passes_test в качестве основы для собственных декораторов:

from django.contrib.auth.decorators import login_required, user_passes_test

user_login_required = user_passes_test(lambda user: user.is_active, login_url='/')

def active_user_required(view_func):
    decorated_view_func = login_required(user_login_required(view_func))
    return decorated_view_func

@active_user_required
def index(request):
    return render(request, 'index.html')

Здесь декоратор user_passes_test возвращает логическое значение is_active, которое обозначает, разрешено ли пользователю авторизовываться на сайте. И параметр login_url: на этот URL-адрес будет перенаправлен пользователь, если авторизация не разрешена. Таким образом мы можем использовать active_user_required.

Если вы хотите разрешить выполнение представления пользователю, обладающему определенной ролью, можно написать декораторы с использованием методов моделей.

def is_recruiter(self):
    if str(self.user_type) == 'Recruiter':
        return True
    else:
        return False

rec_login_required = user_passes_test(lambda u: True if u.is_recruiter else False, login_url='/')

def recruiter_login_required(view_func):
    decorated_view_func = login_required(rec_login_required(view_func), login_url='/')
    return decorated_view_func

@recruiter_login_required
def index(request):
    return render(request, 'index.html')

Здесь is_recruiter — метод модели, который проверяет роль пользователя. Мы используем метод модели в декораторе user_passes_test. Если роль пользователя удовлетворена, то он выполняет эту функцию, в противном случае происходит перенаправление на главную страницу.

Если вы хотите выполнить представление согласно настройкам прав доступа, можно воспользоваться функционалом Django permissions и встроенным декоратором @permission_required.

В метаклассе модели пользователя можно указать права доступа.

from django.contrib.auth.decorators import permission_required

class Meta:
    permissions = (
            ('blog_view', 'can view blog posts and categories'),
            ('blog_edit', 'can edit blog category and post'),
            ("support_view", "can view tickets"),
            ("support_edit", "can edit tickets"),
            ("activity_view", "can view recruiters, applicants, data, posts"),
            ("activity_edit", "can edit data"),
        )


@permission_required('blog.blog_edit')
def my_view(request):
    ...

В основу статьи положен материал Ramya Ambati.