gpt4 book ai didi

google-openid - 如何使用 Python Social Auth 将用户从 OpenID 迁移到 Google OAuth2/OpenID Connect?

转载 作者:行者123 更新时间:2023-12-04 05:34:45 25 4
gpt4 key购买 nike

Google 正在弃用我正在使用的 OpenID 端点(我认为是 v1.0,通过 django_openid_auth 模块),我需要更新我的应用程序并迁移我的用户帐户以使用 Google OAuth2。

我已将应用程序更改为使用 python-social-auth并通过 social.backends.google.GoogleOAuth2 对其进行身份验证成功地。

我编写了一个管道函数来从旧表中查找关联的 OpenID url,这适用于我关心的其他后端,但谷歌:

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'])}

尽我所能从阅读 Google's migration guide 中得知,我需要添加一个 openid.realm到请求,我在settings.py中做了如下:
SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS \
= {'openid.realm': 'http://example.com/'}

但这似乎并没有返回 open_id response 中的值传递到我的管道函数中。

我似乎卡在 Step 3 :
  • 我尝试对后端进行子类化以更改 RESPONSE_TYPE 以添加 id_token但这返回了一个空响应:
    import social.backends.google
    class CustomGoogleOAuth2(social.backends.google.GoogleOAuth2):
    RESPONSE_TYPE = 'code id_token'
  • 我尝试向 https://www.googleapis.com/oauth2/v3/token 创建一个附加请求类似于 this example ,但我真的不知道如何将它放在一起并调试它。

  • 更多细节:
  • 我的老claimed_id Google OpenID 用户的 s 看起来像:https://www.google.com/accounts/o8/id?id=AItOawmAW18QuHDdn6PZzaiI5BWUb84mZzNB9eo
  • 我很乐意使用 social.backends.google.GoogleOpenIdConnect或类似的替代后端,如果这是一个更简单的解决方案。虽然它似乎更接近谷歌文档所谈论的内容,但当我尝试时,我无法让它工作:
  • 我收到 400 错误:此消息类型不允许使用 invalid_request 参数:nonce
  • 我可以通过 nonce使用 social.backends.google.GoogleOpenIdConnect 时出错通过添加 id_tokenRESPONSE_TYPE但后来我得到一个 AuthMissingParameter我的 /complete/google-openidconnect/ 中的错误端点作为请求的 GET 和 POST 为空。 (试过'code id_token'、'token id_token'、'id_token'、...)
  • 我不想使用 social.backends.google.GooglePlusAuth因为这与我当前的登录表单不能很好地集成。
  • 最坏的情况,我应该可以使用 social.pipeline.social_auth.associate_by_email ,但我只有大约 80% 的用户的电子邮件地址,因此留下了相当多的人将拥有一个新帐户并需要支持来手动关联它。

  • 尽我所能,我找不到任何使用 python-social-auth 进行类似迁移的示例,但它一定发生在很多人身上。

    有任何想法吗?

    最佳答案

    解决方案适用于 python social auth 0.1.26

    在 python social auth 的新版本(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

    笔记:
  • get_user_id – 用户的标识符,在所有 Google 帐户中唯一且从不重复使用。
  • request_access_token – 我将 id_token_parsed 添加到响应中,它将在管道中使用。
  • validate_and_return_id_token - 禁用 jwt 验证,因为在谷歌开发者控制台中我已将客户端 ID 注册为 Web 应用程序,所以我没有用于验证此数据的证书。

  • 然后我创建了管道:
    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',
    ...
    )

    关于google-openid - 如何使用 Python Social Auth 将用户从 OpenID 迁移到 Google OAuth2/OpenID Connect?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28717264/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com