Пирамида ACL без прохождения - PullRequest
9 голосов
/ 24 октября 2011

Я действительно мало представляю, как работают ACL. Я знаю, это довольно круто и может сэкономить мне много времени и боли. Но в настоящее время я немного потерян. Все примеры для пирамиды используют обход. Я исключительно использую URL Dispatch. Я не уверен, что понимаю, как я могу построить древовидную структуру ресурсов.

Вот пример кода:

class QuestionFactory(object):

    def __init__(self, request):
        self.__acl__ = default[:]
        self.uid = authenticated_userid(request)

        self.qid = request.matchdict.get('id')
        if self.qid:
            self.question = request.db.questions.find_one({'_id': ObjectId(self.qid)})
            if str(self.question.get('owner')) == self.uid:
                self.__acl__.append((Allow, userid, 'view'))     

Дело в том, что это работает. Но я должен определить новую фабрику для каждого типа ресурсов. Я не уверен, как мне узнать, к какому ресурсу я пытаюсь получить доступ через URL Dispatch и Factory. Я бы увидел что-то подобное

/accounts/{account}   //Owners only but viewable by anyone 
/messages/{message}   //Owners only
/configs/{config}     //Admin only
/pages/{page}         //Admins only but viewable by anyone

Здесь сказано, что у меня будет такая структура

  Root -\
         +-- account
         +-- message
         +-- config
         +-- page

У каждого из этих заводов есть свой специальный acl. Другое дело, что / account является главной страницей. У него нет идентификатора или чего-то еще. Также / account / new также является особым случаем. Это не идентификатор, а вид для создания нового элемента.

Я использую спокойный стиль с требованием GET / PUT / DELETE / POST. Я не совсем уверен, как я должен сопоставить URL-адрес с ресурсом и правильным ACL автоматически. Если я определю в своем корне специальную фабрику, как указано выше, проблем не будет.

редактировать

Я заставил его работать, за исключением некоторых вещей. Я, наконец, думаю, что понимаю, в чем цель траверса Например, у нас есть этот URL: / comments / 9494f0eda / new, / Комментарии / {комментарий} / * новый 1020 *

Нам может понадобиться узел в нашем дереве ресурсов или даже 3 узла.

Сначала RootFactory будет проверяться, а затем в соответствии с нашим обходом. Он получит атрибут комментариев RootFactory, затем «комментарий» фабрики комментариев и «новый» CommentFactory или самого объекта

Я не использую Фабрику как диктовку, как на примере Майкла

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

class RessourceFactory(object):
    def __init__(self, parent, name):

        self.__acl__ = []
        self.__name__ = name
        self.__parent__ = parent

        self.uid = parent.uid
        self.locale = parent.locale
        self.db = parent.db
        self.req = parent.req

Это мой базовый ресурсный объект. На каждом шаге он копирует информацию от родителя к новому дочернему элементу .. Я, конечно, мог бы всплывать в моем атрибуте .. context. parent ._ parent _. Uid, но это просто не так это здорово.

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

/ комментарии

По некоторым причинам он создал мою CommentFactory, но не вернул ее, так как не было необходимости в ключе.

Итак, моя корневая фабрика выглядит примерно так:

class RootFactory(object):

    def __init__(self, request):
        self.__acl__ = default[:]

        self.req = request
        self.db = request.db

        self.uid = authenticated_userid(request)
        self.locale = request.params.get('locale', 'en')

    def __getitem__(self, key):

        if key == 'questions':
            return QuestionFactory(self, 'questions')
        elif key == 'pages':
            return PageFactory(self, 'pages')
        elif key == 'configs':
            return ConfigFactory(self, 'configs')
        elif key == 'accounts':
            return AccountFactory(self, 'accounts')

        return self

если элемент не найден, RootFactory возвращает себя, если нет, возвращает новый Factory. Поскольку я основываю свой код на коде Майкла, для конструктора Factory есть второй параметр. Я не уверен, что сохраню это, так как QuestionFactory хорошо знает, как обрабатывать «вопросы», поэтому нет необходимости называть фабрику здесь. Он должен уже знать свое имя.

class QuestionFactory(RessourceFactory):
    def __init__(self, parent, name):
        RessourceFactory.__init__(self, parent, name)
        self.__acl__.append((Allow, 'g:admin', 'view'))
        self.__acl__.append((Allow, 'g:admin', 'edit'))
        self.__acl__.append((Allow, 'g:admin', 'create'))
        self.__acl__.append((Allow, 'g:admin', 'delete'))
        self.__acl__.append((Allow, Everyone, 'create'))

    def __getitem__(self, key):

        if key=='read':
            return self

        self.qid = key
        self.question = self.db.questions.find_one({'_id': ObjectId(self.qid)})

        if str(self.question.get('owner')) == self.uid:
            log.info('Allowd user %s' % self.uid)
            self.__acl__.append((Allow, self.uid, 'view'))
            self.__acl__.append((Allow, self.uid, 'edit'))
            self.__acl__.append((Allow, self.uid, 'delete'))

        return self

Так вот где почти вся логика пойдет. В init я установил acl, который будет работать для / questions, в getitem, который будет работать для / questions / {id} / *

Так как я возвращаю себя, любой getitem после этой RessourceFactory будет указывать на себя, если я не верну новую Фабрику для какого-то особого случая. Причина в том, что мой контекст - это не просто объект в базе данных или объект.

Мой контекст обрабатывает несколько вещей, таких как идентификатор пользователя, локаль и т. Д. ... когда ACL готов, у меня есть новый объект контекста, готовый к использованию. Это удаляет большую часть логики в представлениях.

Возможно, я мог бы установить события для запроса локали и идентификатора, но это действительно подходит здесь. Если мне нужно что-то новое, мне просто нужно отредактировать мои RootFactory и RessourceFactory, чтобы скопировать их на дочернюю фабрику.

Таким образом, если что-то должно измениться во всех представлениях, нет никакой избыточности вообще.

1 Ответ

6 голосов
/ 25 октября 2011

Похоже, вас интересуют некоторые функции безопасности на уровне объектов / строк, позволяющие просматривать данные только владельцам учетных записей. Я бы сослался на мой предыдущий SO-ответ по этой теме, а также на учебник, над которым я работал для аутентификации в URL Dispatch, который построен вокруг этого ответа. В частности, вы можете посмотреть демонстрационную версию 2.object_security в связанном проекте github, а также документы, объясняющие деревья ресурсов, как часть рендеринга html на моем сайте.

Пирамидальная авторизация для хранимых предметов

https://github.com/mmerickel/pyramid_auth_demo

http://michael.merickel.org/projects/pyramid_auth_demo/

Если у вас есть какие-либо вопросы относительно понимания этих ресурсов, я был бы рад уточнить здесь.

...