谷歌不推荐我使用的OpenID端点(我认为是1.0版本,通过django_openid_auth模块),我需要更新我的应用程序,并迁移我的用户帐户来使用GoogleOAuth2。
我已将应用程序更改为使用python-social-auth,并使其成功地与social.backends.google.GoogleOAuth2进行身份验证。
我编写了一个管道函数,用于从旧表中查找关联的OpenID urls,这适用于我关心的其他后端,但Google:
def associate_legacy_user(backend, response, uid=None, user=None,
*args, **kwargs):
if uid and not user:
# Try to associate accounts registered in the old openid table
identity_url = None
if backend.name == 'google-oauth2':
# TODO: this isn't working
identity_url = response.get('open_id')
else:
# for all other backends, see if there is a claimed_id url
# matching the identity_url use identity_url instead of uid
# as uid may be the user's email or username
try:
identity_url = response.identity_url
except AttributeError:
identity_url = uid
if identity_url:
# raw sql as this is no longer an installed app
user_ids = sql_query.dbquery('SELECT user_id '
'FROM django_openid_auth_useropenid '
'WHERE claimed_id = %s',
(identity_url,))
if len(user_ids) == 1:
return {'user': User.objects.get(id=user_ids[0]['user_id'])}从阅读谷歌迁移指南可以看出,我需要在请求中添加一个openid.realm,我在settings.py中已经这样做了:
SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS \
= {'openid.realm': 'http://example.com/'}但这似乎并没有返回传递给我的管道函数的open_id值。
我好像被困在第三步上了
id_token,但这返回了一个空响应:
导入CustomGoogleOAuth2(social.backends.google.GoogleOAuth2):social.backends.google类RESPONSE_TYPE = 'code id_token‘https://www.googleapis.com/oauth2/v3/token构建一个类似于这个例子的额外请求,但我不知道如何将它组合在一起并进行调试。更多细节:
social.backends.google.GoogleOpenIdConnect或类似的替代后端,如果这是一个更容易的解决方案。虽然它似乎更接近Google文档正在谈论的内容,但当我尝试:时,我无法让它开始工作。nonce添加到social.backends.google.GoogleOpenIdConnect中来克服id_token错误,但是当请求的get和POST为空时,在/complete/google-openidconnect/端点中得到一个AuthMissingParameter错误。(尝试过'code id_token‘、'token id_token’、'id_token‘、.)
social.backends.google.GooglePlusAuth,因为它不能很好地集成到我当前的登录表单中。social.pipeline.social_auth.associate_by_email,但我的电子邮件地址可能只有80%的用户,因此,有相当多的人将有一个新的帐户,并需要支持手动关联。尽管我可能会尝试,但我找不到使用python-social-auth进行类似迁移的人的任何例子,但这肯定发生在很多人身上。
有什么想法吗?
发布于 2015-05-30 11:39:30
解决方案适用于python auth 0.1.26
在python的新版本(0.2.*)中,有GoogleOpenIdConnect,但是它不能正常工作(至少我没有成功)。而且我的项目有一些遗产,所以我不能使用新版本的社交。
我编写了自定义GoogleOpenIdConnect后端:
import datetime
from calendar import timegm
from jwt import InvalidTokenError, decode as jwt_decode
from social.backends.google import GoogleOAuth2
from social.exceptions import AuthTokenError
class GoogleOpenIdConnect(GoogleOAuth2):
name = 'google-openidconnect'
ACCESS_TOKEN_URL = 'https://www.googleapis.com/oauth2/v3/token'
DEFAULT_SCOPE = ['openid']
EXTRA_DATA = ['id_token', 'refresh_token', ('sub', 'id')]
ID_TOKEN_ISSUER = "accounts.google.com"
def user_data(self, access_token, *args, **kwargs):
return self.get_json(
'https://www.googleapis.com/plus/v1/people/me/openIdConnect',
params={'access_token': access_token, 'alt': 'json'}
)
def get_user_id(self, details, response):
return response['sub']
def request_access_token(self, *args, **kwargs):
"""
Retrieve the access token. Also, validate the id_token and
store it (temporarily).
"""
response = self.get_json(*args, **kwargs)
response['id_token_parsed'] = self.validate_and_return_id_token(response['id_token'])
return response
def validate_and_return_id_token(self, id_token):
"""
Validates the id_token according to the steps at
http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation.
"""
try:
id_token = jwt_decode(id_token, verify=False)
except InvalidTokenError as err:
raise AuthTokenError(self, err)
# Verify the token was issued in the last 10 minutes
utc_timestamp = timegm(datetime.datetime.utcnow().utctimetuple())
if id_token['iat'] < (utc_timestamp - 600):
raise AuthTokenError(self, 'Incorrect id_token: iat')
return id_token备注:
然后我创建了管道:
def social_user_google_backwards(strategy, uid, *args, **kwargs):
"""
Provide find user that was connect with google openID, but is logging with google oauth2
"""
result = social_user(strategy, uid, *args, **kwargs)
provider = strategy.backend.name
user = result.get('user')
if provider != 'google-openidconnect' or user is not None:
return result
openid_id = kwargs.get('response', {}).get('id_token_parsed', {}).get('openid_id')
if openid_id is None:
return result
social = _get_google_openid(strategy, openid_id)
if social is not None:
result.update({
'user': social.user,
'is_new': social.user is None,
'google_openid_social': social
})
return result
def _get_google_openid(strategy, openid_id):
social = strategy.storage.user.get_social_auth('openid', openid_id)
if social:
return social
return None
def associate_user(strategy, uid, user=None, social=None, *args, **kwargs):
result = social_associate_user(strategy, uid, user, social, *args, **kwargs)
google_openid_social = kwargs.pop('google_openid_social', None)
if google_openid_social is not None:
google_openid_social.delete()
return result并更改了我的SOCIAL_AUTH_PIPELINE和AUTHENTICATION_BACKENDS设置:
AUTHENTICATION_BACKENDS = (
...
#'social.backends.open_id.OpenIdAuth' remove it
'social_extension.backends.google.GoogleOpenIdConnect', # add it
...
)和
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
# 'social.pipeline.social_auth.social_user', remove it
'social_extension.pipeline.social_user_google_backwards', # add it
'social.pipeline.user.get_username',
...
# 'social.pipeline.social_auth.associate_user', remove it
'social_extension.pipeline.associate_user', # add it
'social.pipeline.social_auth.load_extra_data',
...
)https://stackoverflow.com/questions/28717264
复制相似问题