升级Tornado到4后weibo oauth登录不了
把 Tornado 升级到4后,发现正常运行的微博登录不可以了。
原因是4已经移除 RequestHandler.async_callback and WebSocketHandler.async_callback ,具体见 http://www.tornadoweb.org/en/stable/releases/v4.0.0.html
替换成 functools.partial 就可解决
记得需要先
import functools
修改后的Weibo.py如下
# -*- coding: utf-8 -*- import functools from tornado import gen from tornado import httpclient from tornado import escape from tornado.httputil import url_concat from tornado.concurrent import Future from tornado.auth import OAuth2Mixin, _auth_return_future, AuthError try: import urlparse except ImportError: import urllib.parse as urlparse try: import urllib.parse as urllib_parse except ImportError: import urllib as urllib_parse class WeiboMixin(OAuth2Mixin): _OAUTH_ACCESS_TOKEN_URL = 'https://api.weibo.com/oauth2/access_token' _OAUTH_AUTHORIZE_URL = 'https://api.weibo.com/oauth2/authorize?' @_auth_return_future def get_authenticated_user(self, redirect_uri, client_id, client_secret, code, callback, grant_type='authorization_code', extra_fields=None): http = self.get_auth_http_client() args = { 'redirect_uri': redirect_uri, 'code': code, 'client_id': client_id, 'client_secret': client_secret, 'grant_type': grant_type, } fields = set(['id', 'screen_name', 'profile_image_url']) if extra_fields: fields.update(extra_fields) # self.async_callback http.fetch(self._OAUTH_ACCESS_TOKEN_URL, method='POST', body=urllib_parse.urlencode(args), callback=functools.partial(self._on_access_token, redirect_uri, client_id, client_secret, callback, fields)) def _oauth_request_token_url(self, redirect_uri=None, client_id=None, client_secret=None, code=None, grant_type=None, extra_params=None): pass def _on_access_token(self, redirect_uri, client_id, client_secret, future, fields, response): if response.error: future.set_exception(AuthError('Weibo auth error %s' % str(response))) return args = escape.json_decode(escape.native_str(response.body)) session = { 'access_token': args['access_token'], 'expires': args['expires_in'], 'uid': args['uid'], } # self.async_callback self.weibo_request( path='/users/show.json', callback=functools.partial( self._on_get_user_info, future, session, fields), access_token=session['access_token'], uid=session['uid'] ) def _on_get_user_info(self, future, session, fields, user): if user is None: future.set_result(None) return fieldmap = {} for field in fields: fieldmap[field] = user.get(field) fieldmap.update({'access_token': session['access_token'], 'session_expires': session['expires']}) future.set_result(fieldmap) @_auth_return_future def weibo_request(self, path, callback, access_token=None, uid=None, post_args=None, **args): url = "https://api.weibo.com/2" + path all_args = {} if access_token: all_args['access_token'] = access_token if uid: all_args['uid'] = uid if args: all_args.update(args) if all_args: url += '?' + urllib_parse.urlencode(all_args) # self.async_callback callback = functools.partial(self._on_weibo_request, callback) http = self.get_auth_http_client() if post_args is not None: http.fetch(url, method="POST", body=urllib_parse.urlencode(post_args), callback=callback) else: http.fetch(url, callback=callback) def _on_weibo_request(self, future, response): if response.error: future.set_exception(AuthError('Error response %s fetching %s', response.error, response.request.url)) return future.set_result(escape.json_decode(response.body)) def get_auth_http_client(self): return httpclient.AsyncHTTPClient()
登录代码
class WeiboAuthHandler(SNSBaseHandler, WeiboMixin): @tornado.web.asynchronous @gen.coroutine def get(self): if self.get_argument('code', None): user = yield self.get_authenticated_user( redirect_uri=self.request.full_url(), client_id=self.settings['weibo_api_key'], client_secret=self.settings['weibo_api_secret'], code=self.get_argument('code')) snsId = user['id'] email = '%s@weibo.com' % snsId nickname = user['screen_name'] profileImg= 'http://tp1.sinaimg.cn/%s/180/0/1' % snsId session_expires = int(time.time()) + int(user['session_expires']) result,tp,userId = self.SNSUser(self.SNSType['weibo'],email,nickname,snsId,user['access_token'],json.dumps(user),session_expires,profileImg) if result: expiresDays = int(user['session_expires'])/(3600*24) expiresDays = expiresDays < 1 and 1 or expiresDays self.userLogin(userId,expiresDays) url_next=self.get_argument("next", "/") self.redirect(url_next) else: self.redirect('/login') else: self.authorize_redirect( redirect_uri=self.request.full_url(), client_id=self.settings['weibo_api_key'] )