Давайте поговорим о безопасности.

Существует два самых распространенных подхода к описанию ограничений доступа в информационных системах. Первый — нельзя ничего, кроме функций, явно указанных как разрешенные. Второй — можно все, кроме явно запрещенного. Ни один из подходов не является однозначно лучшим, выбирать нужно в зависимости от особенностей конкретной системы. Если оная состоит преимущественно из публичной части, то удобнее описывать политику доступа через ограничения. Если публичная часть мала, а основное взаимодействие происходит с зарегистрированными пользователями — описываем, наоборот, через набор разрешений. Ну и еще имеет значение то, в какую сторону в данной системе страшнее ошибиться — что-то лишнее разрешить или запретить.

Проблема

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

В текущем версии фрэймворк не особо помогает нам с описанием прав доступа (да и в 1.1 не обещают улучшений по этой части). А именно – доступен только запретительный механизм описания, осуществляемый через навешивание на view-функции декоратора login_required

Примерно так:

from django.contrib.auth.decorator import login_required

@login_required # Доступ ограничен
def some_view(requests):
   # blah-blah-blah

# Доступ свободный
def other_view(requests):
   # blah-blah-blah

Во всей красе проявляются недостатки такого подхода — нужно вешать декоратор на 90% представлений. Плюс к тому, всегда есть риск получить неочевидную дыру в безопасности системы, если забыть поставить декоратор.

Решение

В рамках стремления к лучшему и концепции “сделай сам” разработан способ описывать права через набор разрешений.

from middleware.security import public

# Доступ ограничен, как если бы стоял login_required
def some_view(requests):
   # blah-blah-blah

@public # Доступ свободный
def other_view(requests):
   # blah-blah-blah

Инструкция по установке

  1. Скачиваем модуль security.py и кладем его куда-нибудь. У нас это директория middleware, общая для всех приложений.

  2. В настойках добавляем NonpublicMiddleware

    MIDDLEWARE_CLASSES = (
        ...,
        'middleware.security.NonpublicMiddleware', 
    )
    
  3. По необходимости правим функцию is_public, чтобы изменить логику определения известных публичных view (сейчас это все, находящееся в пакете django, за исключением django.views.generic)

  4. Все, можно пользоваться.

security.py