如何使用龙卷风3.2.2使用GoogleOAuth2Mixin进行谷歌登录授权

时间:2014-07-02 16:51:20

标签: python oauth-2.0 tornado google-oauth

我正在尝试为我的龙卷风应用实施Google Oauth 2.0登录。他们用3.2.2做了一些改动,他们似乎没有明确的指示。以下是我的代码:

class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        user = self.get_secure_cookie('trakr')
        if not user: return None
        return True

class ProductsHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self):
        self.render("products.html")
        return

class GAuthLoginHandler(BaseHandler, tornado.auth.GoogleOAuth2Mixin):
    @tornado.gen.coroutine
    def get(self):
        if self.get_current_user():
            self.redirect('/products')
            return

        if self.get_argument('code', False):
            user = yield self.get_authenticated_user(redirect_uri=settings.google_redirect_url,
                code=self.get_argument('code'))
            if not user:
                self.clear_all_cookies() 
                raise tornado.web.HTTPError(500, 'Google authentication failed')

            access_token = str(user['access_token'])
            http_client = self.get_auth_http_client()
            http_client.fetch('https://www.googleapis.com/oauth2/v1/userinfo?access_token='+access_token, self._save_user_profile)
            return

        elif self.get_secure_cookie('trakr'):
            self.redirect('/products')
            return

        else:
            yield self.authorize_redirect(
                redirect_uri=settings.google_redirect_url,
                client_id=self.settings['google_oauth']['key'],
                scope=['email'],
                response_type='code',
                extra_params={'approval_prompt': 'auto'})

    def _save_user_profile(self, response):
        if not response:
            raise tornado.web.HTTPError(500, "Google authentication failed.")
        user = json.loads(response.body)
        self.set_secure_cookie('trakr', user['email']) 
        self.redirect('/products')

目前我收到以下错误:

[E 140702 12:35:30 ioloop:491] Exception in callback <functools.partial object at 0xa51ff54>
    Traceback (most recent call last):
      File "/usr/local/lib/python2.7/dist-packages/tornado/ioloop.py", line 477, in _run_callback
        callback()
      File "/usr/local/lib/python2.7/dist-packages/tornado/stack_context.py", line 331, in wrapped
        raise_exc_info(exc)
      File "/usr/local/lib/python2.7/dist-packages/tornado/stack_context.py", line 302, in wrapped
        ret = fn(*args, **kwargs)
      File "main.py", line 202, in _save_user_profile
        self.redirect('/')
      File "/usr/local/lib/python2.7/dist-packages/tornado/web.py", line 629, in redirect
        raise Exception("Cannot redirect after headers have been written")
    Exception: Cannot redirect after headers have been written

我不明白我在哪里设置响应标头。

  • 如何解决此问题?
  • 我这样做是对的吗?你有任何示例代码吗?

2 个答案:

答案 0 :(得分:5)

如果有人在看,这是Ben回答后的剧本:

class GAuthLoginHandler(BaseHandler, tornado.auth.GoogleOAuth2Mixin):
    @tornado.gen.coroutine
    def get(self):
        if self.get_current_user():
            self.redirect('/products')
            return

        if self.get_argument('code', False):
            user = yield self.get_authenticated_user(redirect_uri=settings.google_redirect_url,
                code=self.get_argument('code'))
            if not user:
                self.clear_all_cookies() 
                raise tornado.web.HTTPError(500, 'Google authentication failed')

            access_token = str(user['access_token'])
            http_client = self.get_auth_http_client()
            response =  yield http_client.fetch('https://www.googleapis.com/oauth2/v1/userinfo?access_token='+access_token)
            if not response:
                self.clear_all_cookies() 
                raise tornado.web.HTTPError(500, 'Google authentication failed')
            user = json.loads(response.body)
            # save user here, save to cookie or database
            self.set_secure_cookie('trakr', user['email']) 
            self.redirect('/products')
            return

        elif self.get_secure_cookie('trakr'):
            self.redirect('/products')
            return

        else:
            yield self.authorize_redirect(
                redirect_uri=settings.google_redirect_url,
                client_id=self.settings['google_oauth']['key'],
                scope=['email'],
                response_type='code',
                extra_params={'approval_prompt': 'auto'})

答案 1 :(得分:1)

不要混合协程和回调样式。 http_client.fetch块末尾的if self.get_argument('code')调用应使用yield和no callback参数(然后在返回之前内联_save_user_profile方法)