我正在使用Django与Allauth +REST-8月为SPA社会登录,并成功建立Facebook,VK和谷歌授权,但面临一个问题,同时添加Twitter。它以{"code":89,“message”:“无效或过期令牌”结束。}}看来我遗漏了什么东西,因为Twitter的标准登录功能是应该的。
以下是我的尝试:
首先,我设置了Twitter登录端点,如doc中所述:
class TwitterLogin(SocialLoginView):
serializer_class = TwitterLoginSerializer
adapter_class = CustomTwitterOAuthAdapter它具有post方法,期望access_token和token_secret,因此创建了重定向视图以接收来自twitter的重定向,完成登录,并通过模板呈现(带有几行JS行)将内部django令牌设置为浏览器localStorage:
class TwitterReceiveView(APIView):
def get(self, request, *args, **kwargs):
access_token = request.query_params.get('oauth_token')
token_secret = request.query_params.get('oauth_verifier')
params = {'access_token': access_token,
'token_secret': 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}
return render(request, 'account/local_storage_setter.html',
context, content_type='text/html')值得一提的是,我尝试了两种方法来启动进程(获取初始令牌) 1.使用标准的allauth http://0.0.0.0:8080/accounts/twitter/login 2。创建了另一个视图(使用lib 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')发布于 2019-03-15 04:27:23
很好的代码,谢谢你的张贴!
但是,我想补充的是,用户身份验证可以直接从前端完成,并且考虑到您正在编写SPA,这样做似乎是合乎逻辑的,而不是将后端的RESTful重定向到auth,然后发送响应。
我使用了以下基于vue身份验证的JS助手类。创建一个弹出窗口并从回调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)
})
}
}不过,我所采用的方法与你的类似:
其他一切
在任何情况下,谢谢我在js和python中使用了大量的库,但是这只是最好的方法。
https://stackoverflow.com/questions/49199253
复制相似问题