django-rest-auth:使用 google 进行社交登录

Posted

技术标签:

【中文标题】django-rest-auth:使用 google 进行社交登录【英文标题】:django-rest-auth: social login with google 【发布时间】:2016-03-30 12:04:37 【问题描述】:

django-rest-auth 文档讨论了 Facebook 集成,我对此不感兴趣——我关心的是通过 Google 提供社交登录。我已经尝试了很长时间了,我想知道是否有其他人有任何关于他们如何做到这一点的文档……即使只是一个粗略的草图也会有所帮助。到目前为止,我还没有找到此搜索的任何结果。我快到了,但无法让它与 Django 休息框架 (DRF) 可浏览 API 一起工作。

这是我目前所拥有的: 我从 django-rest-auth github 页面上提供的演示项目开始,并将社交登录模板 html 页面修改为只需要“code”输入,而不需要“code”和“access_token”。当我提供有效代码(通过对谷歌的身份验证端点的单独请求获得)时,这可以正常工作;可浏览的 API 在响应中使用“密钥”(我的应用程序的用户 API 令牌)呈现通常的网页。检查 django 管理员,一切正常 - 用户已登录,电子邮件已通过身份验证等。到目前为止一切顺利。

问题在于提供“代码”的起点——以及我首先如何从谷歌获得该代码。当我之前(成功)使用 allauth 包时,我可以简单地单击一个链接,这将“隐形”执行整个 OAuth2 流程(即请求代码,使用该代码获取访问令牌,并使用访问令牌来获取用户的谷歌账户信息)。

为了重新创建无缝流程(即不从代码开始),我想我可以中断 OAuth2 流程并“拦截”从 google 返回的代码,然后将该代码发布到 rest-auth 社交登录 API。为此,我通过重写调度方法创建了一个自定义allauth.socialaccount.providers.oauth2.views.OAuth2CallbackView

class CustomOAuth2CallbackView(OAuth2CallbackView):
    def dispatch(self, request):
        # gets the code correctly:
        code = request.GET['code']

        # rp is of type requests.methods.Response
        rp = requests.post(<REST-AUTH API ENDPOINT>, data = 'code':code)
        return rp

通常,当 google 向您最初提供给 google 的 auth 端点的回调 uri 发送 GET 请求时,会调用此方法。有了这个覆盖,我就能够成功地解析谷歌在该回调中返回的代码。 POST 请求有效,并且在 resp._content 字段中有用户的密钥。但是,它最终无法在 DRF 可浏览 API 中生成预期的视图。

基于深入调用堆栈,我发现rest_framework.views.APIView.dispatch 返回一个rest_framework.response.Response 类型的对象。但是,当上面使用的requests.post 方法完成时,它会返回一个requests.models.Response 类型的实例。结果,它没有正确的属性并且在 django 中间件中失败。例如,它没有acceptable_renderer 属性和'get' 方法(在django.middleware.clickjacking.py 中使用)。可以想象,我可以将这些要求添加到 requests.models.Response (rp) 实例中,但是这种 hack 变得更加杂乱无章。

感谢您提供的任何帮助!

【问题讨论】:

你有什么收获吗? 很遗憾没有。忙于其他事情,它从我的视线中消失了。幸运的是不是关键项目,但我相信其他人可能对此感兴趣。 【参考方案1】:

https://github.com/st4lk/django-rest-social-auth

class SocialLoginSignup(SocialSessionAuthView):
"""
    Mobile user social signup and login api view

    args:
        provider: name of the social network
        access_token: auth token got from the social sites
"""
serializer_class = SocialSignUpSerializer
authentication_classes = (TokenAuthentication,)

def post(self, request, *args, **kwargs):
    serializer = self.serializer_class(data=request.data)
    serializer.is_valid(raise_exception=True)
    provider_name = serializer.validated_data['provider']

    decorate_request(request, provider_name) # assign the provider class object in request

    authed_user = request.user if not request.user.is_anonymous() else None

    token = serializer.validated_data['access_token']

    if self.oauth_v1() and request.backend.OAUTH_TOKEN_PARAMETER_NAME not in serializer.validated_data:
        request_token = parse_qs(request.backend.set_unauthorized_token())
        return Response(request_token)

    try:
        # authentication function get call from assign class object in request
        user = request.backend.do_auth(token, user=authed_user)
    except social_exceptions.AuthException as e:
        raise exceptions.ParseError('error':str(e))
    except social_exceptions.AuthTokenError as e:
        raise exceptions.ParseError('error': str(e))
    except social_exceptions.AuthAlreadyAssociated as e:
        raise exceptions.ParseError('error': str(e))
    except social_exceptions.AuthFailed as e:
        raise exceptions.ParseError('error':str(e))
    except social_exceptions.AuthUnknownError as e:
        raise exceptions.ParseError('error': str(e))
    except social_exceptions.WrongBackend as e:
        raise exceptions.ParseError('error':str(e))
    except Exception as e:
        raise exceptions.ParseError('error': social_message.INVALID_AUTH_TOKEN)

    token, created = Token.objects.get_or_create(user=user)
    return Response('auth_token':token.key)

【讨论】:

以上是关于django-rest-auth:使用 google 进行社交登录的主要内容,如果未能解决你的问题,请参考以下文章

django-rest-auth + django-allauth + angular2

如何在 DRF + django-rest-auth 中使用自定义用户模型保存注册时的额外字段

使用 Django-rest-auth 创建新用户时创建自定义用户模型

使用django-rest-auth自带登录注册api

Django-rest-auth Facebook 注册

有啥方法可以更改登录的 Django-rest-auth 视图?