Торнадо - получение возвращаемого значения из await (несколько обратных вызовов) - PullRequest
0 голосов
/ 07 декабря 2018

Я работаю над приложением с аутентификацией OAuth2 в торнадо.Класс входа выглядит следующим образом:

class IDPLogin(tornado.web.RequestHandler, IDPLoginHandler):
    async def get(self):
        if self.get_argument('code', False):
            access = await self.get_authenticated_user(
                ...
            )
            print(type(access))
            #self.set_secure_cookie('user', self.get_argument('code'))
            #self.redirect('/')
        else:
            await self.authorize_redirect(
                ...
            )

С методом get_authenticated_user, выглядящим следующим образом (два дополнительных обратных вызова для получения всех деталей, необходимых для оценки пользователя):

class IDPHubLoginHandler(tornado.auth.OAuth2Mixin):
    def __init__(self):
        self._OAUTH_AUTHORIZE_URL = "..."
        self._OAUTH_ACCESS_TOKEN_URL = "..."
        self._USERINFO_ENDPOINT = "..."

    async def get_authenticated_user(self, redirect_uri, client_id, client_secret, code):
        http = self.get_auth_http_client()
        body = urllib_parse.urlencode({
            "redirect_uri": redirect_uri,
            "code": code,
            "client_id": client_id,
            "client_secret": client_secret,
            "grant_type": "authorization_code",
        })
        fut = http.fetch(self._OAUTH_ACCESS_TOKEN_URL,
                         method="POST",
                         headers={'Content-Type': 'application/x-www-form-urlencoded'},
                         body=body)
        fut.add_done_callback(wrap(functools.partial(self._on_access_token)))

    def _on_access_token(self, future):
        """Callback function for the exchange to the access token."""
        try:
            response = future.result()
        except Exception as e:
            future.set_exception(AuthError('IDP auth error: %s' % str(e)))
            return

        args = escape.json_decode(response.body)
        # Fetch userinfo
        http = self.get_auth_http_client()
        fut = http.fetch(self._USERINFO_ENDPOINT,
                         method="GET",
                         headers={
                             'Authorization': 'Bearer ' + args['access_token'],
                             'accept': 'application/json'
                         }
        )
        fut.add_done_callback(wrap(functools.partial(self._on_userinfo)))

    def _on_userinfo(self, future):
        response = future.result()
        r_body = escape.json_decode(response.body)
        return r_body

Я хочу иметь возможностьдля доступа к телу, возвращенному в обратном вызове _on_userinfo, но access в классе Login - 'NoneType', и я хотел бы оценить ответ, чтобы либо запретить доступ, либо представить пользователю cookie.

Представленный код успешно получает все необходимые входные данные, однако я пытаюсь понять, как вернуть значения из функции обратного вызова и повторно использовать их в основном классе входа в систему (IDPLogin).Я просмотрел документацию Торнадо и не смог найти ответ.Примеры Oauth2 / OpenID в лучшем случае очень короткие.

Попытка set_result для будущих результатов в asyncio.base_futures.InvalidStateError.

1 Ответ

0 голосов
/ 07 декабря 2018

Нашел другой способ сделать это.Не уверен, что это самый канонический способ сделать это, но, кажется, он выполнил свою работу.

  1. Реализуйте Oauth2 Mixin следующим образом:

    class IDPLoginHandler(tornado.auth.OAuth2Mixin):
    ...
        async def get_authenticated_user(self, redirect_uri, client_id, client_secret, code):
            #do fetching and return future result
        async def get_user_info(self, access_token):
            #do fetching and return future result
    
  2. Последовательный вызов методов с ключевым словом await из основного обработчика входа:

    class IDPLogin(tornado.web.RequestHandler, IDPLoginHandler):
        async def get(self):
            if self.get_argument('code', False):
                response_token = await self.get_authenticated_user(
                    ...
                )
                token = escape.json_decode(response_token.body)['access_token']
                response_userinfo = await self.get_user_info(token)
    
...