Пирамидный ACL без обхода

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

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

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. Другое дело, что / accounts - это главная страница. У него нет идентификатора или чего-то подобного. Также / accounts / new - тоже особый случай. Это не идентификатор, а представление для создания нового элемента.

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

править

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

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

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

. Я не использую Factory как dict, как в примере Майкла

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

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

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

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

/ comments

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

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

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 завершен, у меня есть новый объект контекста, готовый к использованию. Это удаляет большую часть логики в представлениях.

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

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

9
задан Tim Tisdall 9 August 2013 в 03:56
поделиться