Foursquare API oauth2 ошибка авторизации invalid_request - PullRequest
2 голосов
/ 08 января 2012

Я создаю модуль python-tornado для Foursquare oauth2.Это все основные настройки URL:

_OAUTH_ACCESS_TOKEN_URL = "https://foursquare.com/oauth2/access_token"
_OAUTH_AUTHORIZE_URL    = "https://foursquare.com/oauth2/authorize"
_OAUTH_AUTHENTICATE_URL = "https://foursquare.com/oauth2/authenticate"
_BASE_URL = "https://api.foursquare.com/v2"

Это URL, который я нажимаю, он правильно закодирован и в redirect_uri нет неожиданных символов:

https://foursquare.com/oauth2/authorize?redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fauth%2Ffoursquare%2Fconnect&client_id=my_client_id

А потом я получил страшную страницу invalid_request.Никакой дополнительной информации, никаких сообщений об ошибках.

Я также не вижу никакой полезной информации на вкладке "net" в Firebug.

Поэтому мой вопрос:

  • Что я могу сделать для устранения этой проблемы?Есть ли флаг, который я могу установить в URL-адресе, чтобы получить более подробное сообщение об ошибке?

БАЗОВЫЙ КЛАСС TORNADO OAUTH2

class OAuth2Mixin(object):
    """Abstract implementation of OAuth v 2."""

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

        Some providers 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.
        """
        args = {
            "redirect_uri": redirect_uri,
            "client_id": client_id
        }
        if extra_params: args.update(extra_params)
        self.redirect(url_concat(self._OAUTH_AUTHORIZE_URL, args))

    def _oauth_request_token_url(self, redirect_uri= None, client_id = None,
                                 client_secret=None, code=None,
                                 extra_params=None):
        url = self._OAUTH_ACCESS_TOKEN_URL
        args = dict(
            redirect_uri=redirect_uri,
            code=code,
            client_id=client_id,
            client_secret=client_secret,
        )
        if extra_params: args.update(extra_params)
        return url_concat(url, args)   # url_concat is just a string utility that generates GET params given dictionary

ЧЕТВЕРТЫЙ МИКСИН (ОДИН Я СОЗДАЮ)

import tornado.auth
from tornado import httpclient
from tornado import escape

class FoursquareMixin(tornado.auth.OAuth2Mixin):
    _OAUTH_ACCESS_TOKEN_URL = "https://foursquare.com/oauth2/access_token"
    _OAUTH_AUTHORIZE_URL    = "https://foursquare.com/oauth2/authorize"
    _OAUTH_AUTHENTICATE_URL = "https://foursquare.com/oauth2/authenticate"
    _OAUTH_NO_CALLBACKS = False

    _BASE_URL = "https://api.foursquare.com/v2"

    @property
    def httpclient_instance(self):
        return httpclient.AsyncHTTPClient()

    def get_authenticated_user(self, redirect_uri, client_id, client_secret, code, callback):
        args = {
            "redirect_uri": redirect_uri,
            "code": code,
            "client_id": client_id,
            "client_secret": client_secret,
        }

        self.httpclient_instance.fetch(
            self._oauth_request_token_url(**args),
            self.async_callback(self._on_access_token, redirect_uri, client_id, client_secret, callback)
        )


    def _on_access_token(self, redirect_uri, client_id, client_secret, callback, response):
        if response.error:
            logging.warning('Foursquare auth error: %s' % str(response))
            callback(None)
            return

        args = escape.parse_qs_bytes(escape.native_str(response.body))
        session = { "access_token": args["access_token"] }

        self.foursquare_request(
            path="/v2/users/self",
            callback=self.async_callback(self._on_get_user_info, callback, session),
            access_token=session["access_token"]
        )


    def _on_get_user_info(self, callback, session, user):
        if user is None:
            callback(None)
            return

        user.update({
            'first_name': user.get('firstName'),
            'last_name': user.get('lastName'),
            'home_city': user.get('homeCity'),
            'access_token': session['access_token']
        })
        callback(user)


    def foursquare_request(self, path, callback, access_token=None, post_args=None, **args):
        """
        If the request is a POST, post_args should be provided. Query
        string arguments should be given as keyword arguments.

        See: https://developer.foursquare.com/docs/
        """
        url = self.__class__._BASE_URL + path

        all_args = {}
        if access_token:
            all_args["access_token"] = access_token
            all_args.update(args)
            all_args.update(post_args or {})

        if all_args: url += "?" + urllib.urlencode(all_args)

        callback = self.async_callback(self._on_foursquare_request, callback)
        if post_args is not None:
            self.httpclient_instance.fetch(url, method="POST", body=urllib.urlencode(post_args), callback=callback)
        else:
            self.httpclient_instance.fetch(url, callback=callback)


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

1 Ответ

2 голосов
/ 10 января 2012

Вам не хватает response_type = code в запросе на аутентификацию.

Должно выглядеть так:

https://foursquare.com/oauth2/authorize?redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fauth%2Ffoursquare%2Fconnect&response_type=code&client_id=my_client_id

Я написал исчерпывающийБиблиотека Python 4sq, которая обрабатывает танец oauth2 для вас.Возможно, вы избавите себя от необходимости писать собственные или дадите идеи реализации, если вы привержены своей смешанной архитектуре.

https://github.com/mLewisLogic/foursquare

Вот фрагмент кода, который обрабатывает OAuth:

class OAuth(object):
    """Handles OAuth authentication procedures and helps retrieve tokens"""
    def __init__(self, client_id, client_secret, redirect_uri):
        self.client_id = client_id
        self.client_secret = client_secret
        self.redirect_uri = redirect_uri

    def auth_url(self):
        """Gets the url a user needs to access to give up a user token"""
        data = {
            'client_id': self.client_id,
            'response_type': u'code',
            'redirect_uri': self.redirect_uri,
        }
        return u'{AUTH_ENDPOINT}?{params}'.format(
            AUTH_ENDPOINT=AUTH_ENDPOINT,
            params=urllib.urlencode(data))

    def get_token(self, code):
        """Gets the auth token from a user's response"""
        if not code:
            log.error(u'Code not provided')
            return None
        data = {
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'grant_type': u'authorization_code',
            'redirect_uri': self.redirect_uri,
            'code': unicode(code),
        }
        # Build the token uri to request
        url = u'{TOKEN_ENDPOINT}?{params}'.format(
            TOKEN_ENDPOINT=TOKEN_ENDPOINT,
            params=urllib.urlencode(data))
        log.debug(u'GET: {0}'.format(url))
        access_token = None
        # Get the response from the token uri and attempt to parse
        response = _request_with_retry(url)
        return response.get('access_token')
...