【问题标题】:Reuse OAuth1 authorization tokens with rauth通过 rauth 重用 OAuth1 授权令牌
【发布时间】:2013-04-11 07:07:54
【问题描述】:

基于rauth 示例中的twitter-timeline-cli.py 脚本,我使用rauth (OAuth1) 实现了以下twitter 客户端:

from rauth.service import OAuth1Service

class TwitterClient:

    KNOWN_USERS = {
        'user1' : ("xxx", "yyy", "2342354"), # These should be real tokens
    }

    def __init__(self):
        # Get a real consumer key & secret from https://dev.twitter.com/apps/new
        self.twitter = OAuth1Service(
            name='twitter',
            consumer_key=TWITTER_CONSUMER_KEY,
            consumer_secret=TWITTER_CONSUMER_SECRET,
            request_token_url='https://api.twitter.com/oauth/request_token',
            access_token_url='https://api.twitter.com/oauth/access_token',
            authorize_url='https://api.twitter.com/oauth/authorize',
            base_url='https://api.twitter.com/1/')

    def authorize(self):
        request_token, request_token_secret = self.twitter.get_request_token()
        authorize_url = self.twitter.get_authorize_url(request_token)
        print 'Visit this URL in your browser: ' + authorize_url
        pin = raw_input('Enter PIN from browser: ')
        return request_token, request_token_secret, pin

    def init_session(self, user):
        if user in self.KNOWN_USERS :
            request_token, request_token_secret, pin = self.KNOWN_USERS[user]
        else:
            request_token, request_token_secret, pin = self.authorize()
        session = self.twitter.get_auth_session(request_token,
                                                request_token_secret,
                                                method='POST',
                                                data={'oauth_verifier': pin})
        return session

    def list_tweets(self, user):
        session = self.init_session(user)
        params = {'include_rts': 1,  # Include retweets
                  'count': 10}       # 10 tweets

        r = session.get('statuses/home_timeline.json', params=params)

        for i, tweet in enumerate(r.json(), 1):
            handle = tweet['user']['screen_name'].encode('utf-8')
            text = tweet['text'].encode('utf-8')
            print '{0}. @{1} - {2}'.format(i, handle, text)

tc = TwitterClient()

tc.list_tweets('user1')

这个想法是,如果用户不知道,他会被要求授权应用程序。另一方面,如果用户已经授权了这个应用程序,那么授权令牌(request_token、request_token_secret、pin)应该被重用(通常这些令牌将在数据库中;目前,它们被硬编码在脚本)

但这不起作用:

Traceback (most recent call last):
  File "my-twitter-timeline-cli.py", line 56, in <module>
    tc.list_tweets('user1')
  File "my-twitter-timeline-cli.py", line 43, in list_tweets
    session = self.init_session(user)
  File "my-twitter-timeline-cli.py", line 39, in init_session
    data={'oauth_verifier': pin})
  File ".../lib/python2.7/site-packages/rauth/service.py", line 326, in get_auth_session
    **kwargs)
  File ".../lib/python2.7/site-packages/rauth/service.py", line 299, in get_access_token
    process_token_request(r, decoder, key_token, key_token_secret)
  File ".../lib/python2.7/site-packages/rauth/service.py", line 25, in process_token_request
    raise KeyError(PROCESS_TOKEN_ERROR.format(key=bad_key, raw=r.content))
KeyError: 'Decoder failed to handle oauth_token with data as returned by provider. A different decoder may be needed. Provider returned: <?xml version="1.0" encoding="UTF-8"?>\n<hash>\n  <error>Invalid / expired Token</error>\n  <request>/oauth/access_token</request>\n</hash>\n'

是否可以重复使用OAuth1 授权令牌?

【问题讨论】:

    标签: python oauth rauth


    【解决方案1】:

    我误解了整个过程。我们不需要保存request_tokenrequest_token_secretpin,而是需要保存access_tokenaccess_token_secret

    流程其实是:

    1. 使用request_tokenrequest_token_secretpin得到access_tokenaccess_token_secret
    2. 保存access_tokenaccess_token_secret(到数据库,或其他)
    3. 下次再用access_tokenaccess_token_secret

    这是我更正后的测试代码:

    from rauth.service import OAuth1Service
    
    class TwitterClient:
    
        KNOWN_USERS = { # (access_token, access_token_secret)
            'user1' : ("xxx", "yyy")
        }
    
        def __init__(self):
            # Get a real consumer key & secret from https://dev.twitter.com/apps/new
            self.twitter = OAuth1Service(
                name='twitter',
                consumer_key=TWITTER_CONSUMER_KEY,
                consumer_secret=TWITTER_CONSUMER_SECRET,
                request_token_url='https://api.twitter.com/oauth/request_token',
                access_token_url='https://api.twitter.com/oauth/access_token',
                authorize_url='https://api.twitter.com/oauth/authorize',
                base_url='https://api.twitter.com/1/')
    
        def new_session(self):
            request_token, request_token_secret = self.twitter.get_request_token()
            authorize_url = self.twitter.get_authorize_url(request_token)
            print 'Visit this URL in your browser: ' + authorize_url
            pin = raw_input('Enter PIN from browser: ')
            session = self.twitter.get_auth_session(request_token,
                                                    request_token_secret,
                                                    method='POST',
                                                    data={'oauth_verifier': pin})
            print session.access_token, session.access_token_secret # Save this to database
            return session
    
        def reuse_session(self, user):
            access_token, access_token_secret = self.KNOWN_USERS[user]
            session = self.twitter.get_session((access_token, access_token_secret))
            return session
    
        def init_session(self, user):
            if user in self.KNOWN_USERS : session = self.reuse_session(user)
            else                        : session = self.new_session()
            return session
    
        def list_tweets(self, user):
            session = self.init_session(user)
            params = {'include_rts': 1,  # Include retweets
                      'count': 10}       # 10 tweets
    
            r = session.get('statuses/home_timeline.json', params=params)
    
            for i, tweet in enumerate(r.json(), 1):
                handle = tweet['user']['screen_name'].encode('utf-8')
                text = tweet['text'].encode('utf-8')
                print '{0}. @{1} - {2}'.format(i, handle, text)
    
    tc = TwitterClient()
    
    tc.list_tweets('user1')
    

    【讨论】:

    • 非常感谢这段代码。一个问题,不过......如果我对用户验证不感兴趣,而只是使用公共 Stream API 怎么办?我如何绕过oauth_verifier 和整个 PIN 码?
    • 啊哈,Quickbooks API 也有同样的问题,这对我有用!
    猜你喜欢
    • 2014-06-30
    • 2018-06-13
    • 2020-12-22
    • 1970-01-01
    • 2019-03-21
    • 2019-04-30
    • 2018-11-08
    • 2021-12-11
    • 2021-08-29
    相关资源
    最近更新 更多