Невозможно вызвать декоратор в импортированном подклассе приложения cherrpy (дерево сайта)

Я использую Cherpy в качестве веб-сервера и хочу проверить статус входа пользователя в систему, прежде чем возвращать страницу. Это работает с методами в основном классе приложения (в site.py), но дает ошибку, когда я вызываю ту же декорированную функцию для метода в классе, который находится на один уровень глубже в дереве веб-страницы (в отдельном файле).

validate_user() — это функция, используемая в качестве декоратора. Он либо передает пользователя на страницу, либо отправляет его на страницу с ограниченным доступом 401 как cherrypy.Tool, например:

from user import validate_user
cherrypy.tools.validate_user = cherrypy.Tool('before_handler', validate_user)

Я присоединяю различные разделы сайта к классу приложения основного файла site.py, назначая экземпляры подклассов в качестве переменных соответственно:

from user import UserAuthentication

class Root:
    user = UserAuthentication() # maps user/login, user/register, user/logout, etc
    admin = Admin()
    api = Api()

    @cherrypy.expose
    @cherrypy.tools.validate_user()
    def how_to(self, **kw):
        from other_stuff import how_to_page
        return how_to_page(kw) 

Это, однако, не работает, когда я пытаюсь использовать validate_user() внутри разделов Admin или Api или Analysis. Они находятся в отдельных файлах.

import cherrypy

class Analyze:
    @cherrypy.expose
    @cherrypy.tools.validate_user() #### THIS LINE GIVES ERROR ####
    def explore(self, *args, **kw): # @addkw(fetch=['uid'])
        import explore
        kw['uid'] = cherrypy.session.get('uid',-1)
        return explore.explorer(args, kw)

Ошибка в том, что в cherrypy.tools нет функции или метода validate_user. Но другие вещи, которые я назначаю в site.py, появляются здесь в cherrypy. По какой причине я не могу использовать этот инструмент в отдельном файле, который является частью моей общей карты сайта?

Если это важно, функция validate_user() просто просматривает файл cherrypy.request.cookie, находит значение «session_token», сравнивает его с нашей базой данных и передает его, если идентификатор совпадает.

Извините, я не знаю, являются ли страницы Analyze() и Api() и User() подклассами, или вложенными классами, или расширенными методами, или чем-то еще. Поэтому я не могу дать этому точное название. Нужно ли мне как-то передавать им родительский класс?


person Marc Maxmeister    schedule 18.12.2017    source источник
comment
Я должен отметить, что это продолжение моего предыдущего вопроса stackoverflow.com/questions/47840006/ и вдохновлен этим примером stackoverflow.com/questions/6552025/   -  person Marc Maxmeister    schedule 18.12.2017
comment
Где происходит задание cherrypy.tools.validate_user = cherrypy.Tool('before_handler', validate_user)? Если он не находится в модуле, который импортируется при запуске вашего второго класса, то присваивание никогда не произойдет, и вы не сможете получить доступ к декоратору validate_user, даже если у вас есть доступ к тому месту, где оно было бы, если бы присваивание было Выполнено. Может быть просто добавить дополнительный импорт во второй файл, чтобы задание выполнялось. Это также может быть признаком того, что вам следует оставить декоратор в другом месте, а не писать в cherypy.tools.   -  person Blckknght    schedule 22.12.2017
comment
назначение cherrypy.tools.validate_user = cherrypy.Tool('before_handler', validate_user) происходит в site.py, файле верхнего уровня, который предположительно загружается при загрузке сервера (до того, как он вызовет класс Root, где создается экземпляр второго класса)   -  person Marc Maxmeister    schedule 22.12.2017


Ответы (1)


Проблема здесь в том, что Python обрабатывает все, кроме тела функции/метода во время импорта. Таким образом, в site.py, когда вы выполняете import user (или from user import <anything>), это приводит к тому, что весь модуль user обрабатывается прежде, чем интерпретатор Python доберется до определения инструмента validate_user, включая декоратор, который пытается для доступа к этому инструменту по значению (а не по ссылке).

В CherryPy есть еще один механизм для оформления функций с помощью конфигурации, которая активирует инструменты для этих обработчиков. Вместо @cherrypy.tools.validate_user используйте:

@cherrypy.config(**{"tools.validate_user.on": True})

Этот декоратор работает, потому что вместо того, чтобы обращаться к validate_user из cherrypy.tools, чтобы установить себя в обработчик, вместо этого он настраивает CherryPy для установки этого инструмента в обработчик позже, когда обработчик вызывается.

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

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

person Jason R. Coombs    schedule 21.12.2017
comment
отлично - я украсю этим сам класс и попытаюсь создать классы, в которых все URL-адреса требуют аутентификации. - person Marc Maxmeister; 22.12.2017