python-social-auth无法获得正确的Google OAuth2详细信息

Vla*_*zki 7 django django-socialauth google-login python-2.7 python-social-auth

我想使用python-social-authDjango中的Google Plus登录功能登录用户.从我的网站登录时,一切正常,并将正确的详细信息添加到数据库中.

但是,我也希望从我的Android应用程序进行身份验证.用户登录应用程序,然后应用程序将访问令牌发送到django API,后者根据以下代码处理登录过程,该文档根据文档进行调整:

@csrf_exempt
@serengeti_api_request
@psa('social:complete')
def login_social_token(request, backend):
    # Ensure the token has been specified.
    token = request.META.get('HTTP_ACCESSTOKEN')
    if token is None:
        raise SerengetiApiRequestException('Access token is missing!')

    # Login the user for this session
    user = request.backend.do_auth(token)
    if user is None:
        raise SerengetiApiRequestException('Could not authenticate user!')

    login(request, user)

    # Store the email address if one has been specified (e.g. Twitter)
    email = request.META.get('HTTP_EMAIL')
    if email is not None:
        user.email = email
        user.save()

    # Prepare the parameters to be returned
    response = dict({
        'id': user.id,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'api_key': request.session.session_key,
    })

    # Return a 200 status code to signal success.
    return HttpResponse(json.dumps(response, indent=4), status=200)
Run Code Online (Sandbox Code Playgroud)

从网站登录时,该social_auth_usersocialauth表包含:

id | provider      | uid       | extra_data
==========================================
10 | google-oauth2 | <myemail> | {"token_type": "Bearer", "access_token": "<token>", "expires": 3600}
Run Code Online (Sandbox Code Playgroud)

但是,使用上述函数从应用程序登录时,操作完成正常,但表中的条目如下所示:

id | provider      | uid     | extra_data
=========================================
10 | google-oauth2 | <empty> | {"access_token": "", "expires": null}
Run Code Online (Sandbox Code Playgroud)

此外,该auth_user表格包含username类似eeed494412obfuscated48bc47dd9b而非Google Plus用户名,且该email字段为空.

我做错了什么,如何获得与网站相同的功能?

我想提一下,我已经从Android应用程序实现了Facebook和Twitter身份验证,它调用了上述功能并存储了正确的详细信息,只有Google Plus引起了问题.

mar*_*nas 5

只是想分享一种替代方法。这个例子非常原始,并没有涵盖所有情况(例如失败的身份验证)。但是,它应该足够深入地了解如何完成 OAuth2 身份验证。

获取客户 ID

从 OAuth2 服务提供商(例如 Google)获取 CLIENT ID 并配置重定向 URL。

我假设你已经这样做了。

创建登录/注册链接

您需要在视图中生成登录/注册链接。它应该是这样的:

https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={{CLIENT_ID}}&redirect_uri={{REDIRECT_URL}}&scope=email
Run Code Online (Sandbox Code Playgroud)

将 {{CLIENT_ID}} 和 {{REDIRECT_URL}} 替换为您在上一步中获得的详细信息。

创建新视图

urls.py添加类似:

url(r'^oauth2/google/$', views.oauth2_google),
Run Code Online (Sandbox Code Playgroud)

在您views.py创建一个方法中:

def oauth2_google(request):

    # Get the code after a successful signing
    # Note: this does not cover the case when authentication fails
    CODE = request.GET['code']

    CLIENT_ID = 'xxxxx.apps.googleusercontent.com' # Edit this
    CLIENT_SECRET = 'xxxxx' # Edit this
    REDIRECT_URL = 'http://localhost:8000/oauth2/google' # Edit this

    if CODE is not None:
        payload = {
            'grant_type': 'authorization_code', 
            'code': CODE, 
            'redirect_uri': REDIRECT_URL, 
            'client_id': CLIENT_ID, 
            'client_secret': CLIENT_SECRET
            }

        token_details_request = requests.post('https://accounts.google.com/o/oauth2/token', data=payload)
        token_details = token_details_request.json()
        id_token = token_details['id_token']
        access_token = token_details['access_token']

        # Retrieve the unique identifier for the social media account
        decoded = jwt.decode(id_token, verify=False)
        oauth_identifier = decoded['sub']

        # Retrieve other account details
        account_details_request = requests.get('https://www.googleapis.com/plus/v1/people/me?access_token=' + access_token)
        account_details = account_details_request.json()
        avatar = account_details['image']['url']

        # Check if the user already has an account with us
        try:
            profile = Profile.objects.get(oauth_identifier=oauth_identifier)
            profile.avatar = avatar
            profile.save()
            user = profile.user
        except Profile.DoesNotExist:
            user = User.objects.create_user()           
            user.save()
            profile = Profile(user=user, oauth_identifier=oauth_identifier, avatar=avatar)
            profile.save()

        user.backend = 'django.contrib.auth.backends.ModelBackend'
        login(request, user)

        return redirect('/')
Run Code Online (Sandbox Code Playgroud)

您可能需要以下导入:

from django.shortcuts import redirect
import jwt # PyJWT==0.4.1
import requests # requests==2.5.0
import json
Run Code Online (Sandbox Code Playgroud)


Vla*_*zki 1

我终于自己弄清楚了。根据Android的Google Plus文档中的这篇文章,我在Android应用程序中发出请求时还需要请求 plus.profile.emails.read范围。添加此内容后,python-social-auth代码成功地将电子邮件正确存储在uid字段中。这使得它能够识别同一用户,无论是从网站还是应用程序登录,这正是我所需要的。这是我使用的范围字符串:

String scopes = "oauth2:" + Plus.SCOPE_PLUS_LOGIN + " https://www.googleapis.com/auth/plus.profile.emails.read";
Run Code Online (Sandbox Code Playgroud)

但是,该extra_data字段仍然包含我上面提到的值。我相信这是因为还需要请求离线访问,这将允许 Google Plus 将丢失的字段传递回python-django-auth. 更多详情可在这找到