Djangorestauth+Allauth Twitter。错误89。无效或过期的令牌

2024-05-18 07:33:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用Django和Allauth+restauth进行SPA社交登录,并成功地设置了Facebook、VK和Google授权,但在添加Twitter时遇到了一个问题。结果是{“code”:89,“message”:“Invalid or expired token.”} 我好像漏掉了什么东西,因为标准的Twitter登录是正常的

以下是我的尝试:

首先,我按照doc:

class TwitterLogin(SocialLoginView):
    serializer_class = TwitterLoginSerializer
    adapter_class = CustomTwitterOAuthAdapter

它具有post方法,需要access_token和token_secret 所以redirect view被创建来接收来自twitter的redirect,完成登录并通过template render(带有几行JS行)将内部django token设置为browser localStorage:

^{pr2}$

必须提到,我尝试了两种方法来启动进程(获取初始令牌) 1使用标准allauth urlhttp://0.0.0.0:8080/accounts/twitter/login 2创建了另一个视图(使用lib python oauth2),可从SPA使用:

class TwitterGetToken(APIView):

    def get(self, request, *args, **kwargs):
        request_token_url = 'https://api.twitter.com/oauth/request_token'
        authorize_url = 'https://api.twitter.com/oauth/authorize'

        app = SocialApp.objects.filter(name='Twitter').first()
        if app and app.client_id and app.secret:
            consumer = oauth.Consumer(app.client_id, app.secret)
            client = oauth.Client(consumer)

            resp, content = client.request(request_token_url, "GET")
            if resp['status'] != '200':
                raise Exception("Invalid response {}".format(resp['status']))

            request_token = dict(urllib.parse.parse_qsl(content.decode("utf-8")))

            twitter_authorize_url = "{0}?oauth_token={1}"\
                .format(authorize_url, request_token['oauth_token'])

            return redirect(twitter_authorize_url)

        raise Exception("Twitter app is not set up")

我甚至尝试为FacebookLoginView编写get方法,并将twitter回调直接传递给它

class TwitterLogin(SocialLoginView):
    serializer_class = TwitterLoginSerializer
    adapter_class = TwitterOAuthAdapter

    def get(self, request, *args, **kwargs):
        data = {
            'access_token': request.query_params.get('oauth_token'),
            'token_secret': request.query_params.get('oauth_verifier')
        }
        self.request = request
        self.serializer = self.get_serializer(data=data,
                                              context={'request': request})
        self.serializer.is_valid(raise_exception=True)

        self.login()
        return self.get_response()

所有的方法都导致了我提到的错误。你能就我的情况给点建议吗。提前谢谢你!在

更新: 以下是我的工作方式:

import json
import requests
import urllib.parse
import oauth2 as oauth
from requests_oauthlib import OAuth1Session

from django.urls import reverse
from django.conf import settings
from django.shortcuts import redirect, render
from rest_framework.views import APIView
from allauth.socialaccount.models import SocialApp
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter, TwitterAPI
from rest_auth.social_serializers import TwitterLoginSerializer
from rest_auth.registration.views import SocialLoginView


class TwitterGetToken(APIView):
    '''
    Initiates Twitter login process
    Requests initial token and redirects user to Twitter
    '''

    def get(self, request, *args, **kwargs):
        request_token_url = 'https://api.twitter.com/oauth/request_token'
        authorize_url = 'https://api.twitter.com/oauth/authorize'

        app = SocialApp.objects.filter(name='Twitter').first()
        if app and app.client_id and app.secret:
            consumer = oauth.Consumer(app.client_id, app.secret)
            client = oauth.Client(consumer)

            resp, content = client.request(request_token_url, "GET")
            if resp['status'] != '200':
                raise Exception("Invalid response {}".format(resp['status']))

            request_token = dict(urllib.parse.parse_qsl(content.decode("utf-8")))

            twitter_authorize_url = "{0}?oauth_token={1}"\
                .format(authorize_url, request_token['oauth_token'])

            return redirect(twitter_authorize_url)

        raise Exception("Twitter app is not set up")



class TwitterLogin(SocialLoginView):
    '''
    Takes the final twitter access token, secret
    Returns inner django Token
    '''
    serializer_class = TwitterLoginSerializer
    adapter_class = TwitterOAuthAdapter


class TwitterReceiveView(APIView):
    '''
    Receives Twitter redirect, 
    Requests access token
    Uses TwitterLogin to logn and get django Token
    Renders template with JS code which sets django Token to localStorage and redirects to SPA login page
    '''

    def get(self, request, *args, **kwargs):
        access_token_url = 'https://api.twitter.com/oauth/access_token'
        callback_uri = settings.DOMAIN + '/accounts/twitter/login/callback/'

        app = SocialApp.objects.filter(name='Twitter').first()
        client_key = app.client_id
        client_secret = app.secret

        oauth_session = OAuth1Session(client_key,
                                      client_secret=client_secret,
                                      callback_uri=callback_uri)

        redirect_response = request.get_full_path()
        oauth_session.parse_authorization_response(redirect_response)
        token = oauth_session.fetch_access_token(access_token_url)

        params = {'access_token': token['oauth_token'],
                  'token_secret': token['oauth_token_secret']}
        try:
            result = requests.post(settings.DOMAIN + reverse('tw_login'),
                                   data=params).text
            result = json.loads(result)
        except (requests.HTTPError, json.decoder.JSONDecodeError):
            result = {}
        access_token = result.get('access_token')
        context = {'access_token': access_token,
                   'domain': settings.DOMAIN}
        return render(request, 'account/local_storage_setter.html',
                      context, content_type='text/html')

Tags: importselfclienttokenappurlgetsecret
1条回答
网友
1楼 · 发布于 2024-05-18 07:33:23

伟大的代码,谢谢你的张贴!在

不过,我想补充的是,用户身份验证可以直接从前端完成,而且考虑到您正在编写一个SPA,这样做似乎是合乎逻辑的,而不是将您的后端(这打破了RESTful的概念)重定向到auth,然后发送响应。在

我使用了以下基于vue authenticate的JS helper类。弹出并从回调url获取信息

export default class OAuthPopup {
  constructor(url, name, redirectURI) {
    this.popup = null
    this.url = url
    this.name = name
    this.redirectURI = redirectURI
  }

  open() {
    try {
      this.popup = window.open(this.url, this.name)
      if (this.popup && this.popup.focus) {
        this.popup.focus()
      }
      return this.pooling()
    } catch(e) {
      console.log(e)
    }
  }

  pooling() {
    return new Promise((resolve, reject) => {
      let poolingInterval = setInterval(() => {
        if (!this.popup || this.popup.closed || this.popup.closed === undefined) {
          clearInterval(poolingInterval)
          poolingInterval = null
          reject(new Error('Auth popup window closed'))
        }

        try {
          var popupLocation = this.popup.location.origin + this.popup.location.pathname
          if (popupLocation == this.redirectURI) {
            if (this.popup.location.search || this.popup.location.hash ) {

              const urlParams = new URLSearchParams(this.popup.location.search);

              var params = {
                oauth_token: urlParams.get('oauth_token'),
                oauth_verifier: urlParams.get('oauth_verifier'),
                url: this.popup.location.href
              }

              if (params.error) {
                reject(new Error(params.error));
              } else {
                resolve(params);
              }

            } else {
              reject(new Error('OAuth redirect has occurred but no query or hash parameters were found.'))
            }

            clearInterval(poolingInterval)
            poolingInterval = null
            this.popup.close()
          }
        } catch(e) {
          // Ignore DOMException: Blocked a frame with origin from accessing a cross-origin frame.
        }
      }, 250)
    })
  }
}

不过,我遵循的方法与您的方法相似:

  1. 我向TwitterGetToken发出GET请求,并将Twitter身份验证url作为响应返回
  2. 我使用前端响应中的url打开一个弹出窗口,允许用户进行身份验证
  3. 我向TwitterReceiveView发出POST请求,并在twitter auth之后附加响应url

其他的一切都会正常进行,用户会得到一个访问密钥。在

无论如何, 谢谢,我在js和python中处理了大量的库,但这只是最好的方法

相关问题 更多 >