简体   繁体   English

尝试使用Tornado Web验证保管箱

[英]Trying to oauth dropbox with Tornado Web

Here is my mixin file: 这是我的混合文件:

import base64
import binascii
import hashlib
import hmac
import logging
import time
import urllib
import urlparse
import uuid
import tornado.web
import tornado.auth
from tornado import httpclient
from tornado import escape
from tornado.httputil import url_concat
from tornado.util import bytes_type, b

class DropboxMixin(tornado.auth.OAuthMixin):
    """ Dropbox  OAuth authentication.
    """
    _OAUTH_REQUEST_TOKEN_URL = "https://api.dropbox.com/1/oauth/request_token"
    _OAUTH_ACCESS_TOKEN_URL = "https://api.dropbox.com/1/oauth/access_token"
    _OAUTH_AUTHORIZE_URL = "https://www.dropbox.com/1/oauth/authorize"

    def authorize_redirect(self, callback_uri=None, extra_params=None,
                           http_client=None):
        """Redirects the user to obtain OAuth authorization for this service.

        Twitter and FriendFeed both require that you register a Callback
        URL with your application. You should call this method to log the
        user in, and then call get_authenticated_user() in the handler
        you registered as your Callback URL to complete the authorization
        process.

        This method sets a cookie called _oauth_request_token which is
        subsequently used (and cleared) in get_authenticated_user for
        security purposes.
        """
        if callback_uri and getattr(self, "_OAUTH_NO_CALLBACKS", False):
            raise Exception("This service does not support oauth_callback")
        if http_client is None:
            http_client = httpclient.AsyncHTTPClient()
        http_client.fetch(
                          self._oauth_request_token_url(),
                          self.async_callback(
                                self._on_request_token, self._OAUTH_AUTHORIZE_URL,
                                callback_uri))

    def get_authenticated_user(self, callback, http_client=None):
        """Gets the OAuth authorized user and access token on callback.

        This method should be called from the handler for your registered
        OAuth Callback URL to complete the registration process. We call
        callback with the authenticated user, which in addition to standard
        attributes like 'name' includes the 'access_key' attribute, which
        contains the OAuth access you can use to make authorized requests
        to this service on behalf of the user.

        """
        request_key = escape.utf8(self.get_argument("oauth_token"))
        oauth_verifier = self.get_argument("oauth_verifier", None)
        request_cookie = self.get_cookie("_oauth_request_token")
        if not request_cookie:
            logging.warning("Missing OAuth request token cookie")
            callback(None)
            return
        self.clear_cookie("_oauth_request_token")
        cookie_key, cookie_secret = [base64.b64decode(escape.utf8(i)) for i in request_cookie.split("|")]
        if cookie_key != request_key:
            logging.info((cookie_key, request_key, request_cookie))
            logging.warning("Request token does not match cookie")
            callback(None)
            return
        token = dict(key=cookie_key, secret=cookie_secret)
        if oauth_verifier:
            token["verifier"] = oauth_verifier
        if http_client is None:
            http_client = httpclient.AsyncHTTPClient()
        http_client.fetch(self._oauth_access_token_url(token),
                          self.async_callback(self._on_access_token, callback))

    def dropbox_request(self, path, callback, access_token=None,
                        post_args=None, **args):
        # Add the OAuth resource request signature if we have credentials
        url = "http://api.dropbox.com/1" + path

If anyone cares the url should read https://api.dropbox.com/1 " + path 如果有人在乎该网址,则应阅读https://api.dropbox.com/1 “ +路径

        if access_token:
            all_args = {}
            all_args.update(args)
            all_args.update(post_args or {})
            method = "POST" if post_args is not None else "GET"
            oauth = self._oauth_request_parameters(
                url, access_token, all_args, method=method)
            args.update(oauth)
        if args: url += "?" + urllib.urlencode(args)
        callback = self.async_callback(self._on_dropbox_request, callback)
        http = httpclient.AsyncHTTPClient()
        if post_args is not None:
            http.fetch(url, method="POST", body=urllib.urlencode(post_args),
                       callback=callback)
        else:
            http.fetch(url, callback=callback)

    def _oauth_request_token_url(self, callback_uri= None, extra_params=None):
        consumer_token = self._oauth_consumer_token()
        url = self._OAUTH_REQUEST_TOKEN_URL
        args = dict(
            oauth_consumer_key=consumer_token["key"],
            oauth_signature_method="HMAC-SHA1",
            oauth_timestamp=str(int(time.time())),
            oauth_nonce=binascii.b2a_hex(uuid.uuid4().bytes),
            oauth_version=getattr(self, "_OAUTH_VERSION", "1.0"),
        )
        signature = _oauth_signature(consumer_token, "GET", url, args)

        args["oauth_signature"] = signature
        return url + "?" + urllib.urlencode(args)

    def _oauth_access_token_url(self, request_token):
        consumer_token = self._oauth_consumer_token()
        url = self._OAUTH_ACCESS_TOKEN_URL
        args = dict(
            oauth_consumer_key=consumer_token["key"],
            oauth_token=request_token["key"],
            oauth_signature_method="HMAC-SHA1",
            oauth_timestamp=str(int(time.time())),
            oauth_nonce=binascii.b2a_hex(uuid.uuid4().bytes),
            oauth_version=getattr(self, "_OAUTH_VERSION", "1.0"),
        )
        if "verifier" in request_token:
          args["oauth_verifier"]=request_token["verifier"]

        signature = _oauth_signature(consumer_token, "GET", url, args,
                                     request_token)

        args["oauth_signature"] = signature
        return url + "?" + urllib.urlencode(args)

    def _on_dropbox_request(self, callback, response):
        if response.error:
            print("Error response %s fetching %s", response.error,
                            response.request.url)
            callback(None)
            return
        callback(escape.json_decode(response.body))

    def _oauth_consumer_token(self):
        self.require_setting("dropbox_consumer_key", "Dropbox OAuth")
        self.require_setting("dropbox_consumer_secret", "Dropbox OAuth")
        return dict(
            key=self.settings["dropbox_consumer_key"],
            secret=self.settings["dropbox_consumer_secret"])

    def _oauth_get_user(self, access_token, callback):
        callback = self.async_callback(self._parse_user_response, callback)
        self.dropbox_request(
            "/account/info",
            access_token=access_token,
            callback=callback)

    def _oauth_request_parameters(self, url, access_token, parameters={},
                                  method="GET"):
        """Returns the OAuth parameters as a dict for the given request.

        parameters should include all POST arguments and query string arguments
        that will be sent with the request.
        """
        consumer_token = self._oauth_consumer_token()
        base_args = dict(
            oauth_consumer_key=consumer_token["key"],
            oauth_token=access_token["key"],
            oauth_signature_method="HMAC-SHA1",
            oauth_timestamp=str(int(time.time())),
            oauth_nonce=binascii.b2a_hex(uuid.uuid4().bytes),
            oauth_version=getattr(self, "_OAUTH_VERSION", "1.0"),
        )
        args = {}
        args.update(base_args)
        args.update(parameters)
        signature = _oauth_signature(consumer_token, method, url, args,
                                         access_token)
        base_args["oauth_signature"] = signature
        return base_args

    def _parse_user_response(self, callback, user):
        if user:
            user["username"] = user["display_name"]
        callback(user)

def _oauth_signature(consumer_token, method, url, parameters={}, token=None):
    """Calculates the HMAC-SHA1 OAuth signature for the given request.

    See http://oauth.net/core/1.0/#signing_process
    """
    parts = urlparse.urlparse(url)
    scheme, netloc, path = parts[:3]
    normalized_url = scheme.lower() + "://" + netloc.lower() + path

    base_elems = []
    base_elems.append(method.upper())
    base_elems.append(normalized_url)
    base_elems.append("&".join("%s=%s" % (k, _oauth_escape(str(v)))
                               for k, v in sorted(parameters.items())))
    base_string =  "&".join(_oauth_escape(e) for e in base_elems)

    key_elems = [escape.utf8(consumer_token["secret"])]
    key_elems.append(escape.utf8(token["secret"] if token else ""))
    key = b("&").join(key_elems)

    hash = hmac.new(key, escape.utf8(base_string), hashlib.sha1)
    return binascii.b2a_base64(hash.digest())[:-1]

def _oauth_escape(val):
    if isinstance(val, unicode):
        val = val.encode("utf-8")
    return urllib.quote(val, safe="~")


def _oauth_parse_response(body):
    p = escape.parse_qs(body, keep_blank_values=False)
    token = dict(key=p[b("oauth_token")][0], secret=p[b("oauth_token_secret")][0])

    # Add the extra parameters the Provider included to the token
    special = (b("oauth_token"), b("oauth_token_secret"))
    token.update((k, p[k][0]) for k in p if k not in special)
    return token

My View 我的观点

class DropboxIndex(BaseHandler, DropboxMixin):
    @tornado.web.asynchronous
    def get(self):
        if self.get_argument("oauth_token", None):
            self.get_authenticated_user(self.async_callback(self._on_dbox_auth))
            return
        self.authorize_redirect()

    def _on_dbox_auth(self, token):
        from pprint import pprint
        pprint(token)
        self.redirect("/app/dropbox")

My URL Patterns 我的网址格式

patterns = [
    (r"/", Index),
    (r"/help/?", Help),
    # User authentication
    (r"/user/login/?", Login),
    (r"/user/logout/?", LogoutHandler),
    (r"/user/edit/?", IdentityIndex),
    (r"/user/register/?", Register),
    (r"/user/twitter/auth/?", TwitterLogin),
    #(r"/user/google/auth/?", GoogleLogin),
    (r"/user/facebook/auth/?", FacebookLogin),
    (r"/app/dropbox/?", DropboxIndex),
    (r"/app/dropbox/account/?", DropboxAccount),
    (r"/social/?", SocialIndex),
    (r"/api/tweets/?", apiSocialTweets),
    (r"/media/(.*)", tornado.web.StaticFileHandler, {"path" : static_serve}), 
]

Everything works except being brought back to my callback uri with the oauth_token. 一切正常,除了使用oauth_token带回到我的回调uri。 I see the oauth_token in the query and can authorize my app with dropbox.. i just can't get the oauth_token back and usuable 我在查询中看到了oauth_token,可以使用保管箱授权我的应用程序。我只是无法将oauth_token取回并可用

Well, this is a pretty huge piece of code to spend time on, so excuse me if my answer doesn't help much - 好吧,这是一段花费大量时间的代码,请原谅我,如果我的回答没有太大帮助-

Urllib / Urllib2 are pretty much incompatible with handling asynchronous requests. Urllib / Urllib2与处理异步请求几乎不兼容。 You can follow up this question to know why and the solution if you have to use urllib. 您可以跟进问题,以了解原因和解决方法(如果必须使用urllib)。

What I would suggest is to use httplib instead in your code, do comment if this helps or you want to know more. 我建议在代码中使用httplib代替,如果有帮助或者您想了解更多信息,请添加注释。

Thanks Sushant 谢谢Sushant

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM