Python 社交身份验证、Google 和刷新令牌

Python Social Auth, Google, and refresh token

在个人项目中,我尝试使用 Django 作为我的前端,然后允许用户以特定形式输入的数据被复制到 google sheets。

Google自己的文档推荐使用https://github.com/google/oauth2client which is now deprecated, and the docs have not been updated. With this, I have started attempting to use Python Social Auth and Gspread。为了使 Gspread 能够正常运行,我不仅需要能够向其传递访问令牌,还需要能够向其传递刷新令牌。 Python 然而,Social Auth 并未将刷新令牌与 "extra data" 的其余部分一起保留。查看保存的数据和路由到的 URL,在我看来更像是通过 Google+.

路由的某个地方

我的 Django 设置文件中有以下配置:

AUTHENTICATION_BACKENDS = (
    'social_core.backends.google.GoogleOAuth2',
    'django.contrib.auth.backends.ModelBackend',
)

SOCIAL_AUTH_PIPELINE = (
    'social_core.pipeline.social_auth.social_details',
    'social_core.pipeline.social_auth.social_uid',
    'social_core.pipeline.social_auth.social_user',
    'social_core.pipeline.user.get_username',
    'social_core.pipeline.user.create_user',
    'social_core.pipeline.social_auth.associate_user',
    'social_core.pipeline.social_auth.load_extra_data',
    'social_core.pipeline.user.user_details',
    'social_core.pipeline.social_auth.associate_by_email',
)    

SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '...'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '...'
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['https://www.googleapis.com/auth/spreadsheets']

确实 python-social-auth 会使用 Google+ 平台的一些位,至少 API 来检索有关用户填写帐户的详细信息。

从你的设置中,我看到你在底部有 associate_by_email,在那个时候,那个时候它没有用,因为用户已经被创建了,如果你真的打算使用它,它必须在create_user之前,你可以查看DEFAULT_PIPELINE作为参考。

为了从 google 得到一个 refresh_token,你需要告诉它你想要一个,为此你需要设置 offline 访问类型:

SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {
  'access_type': 'offline'
}

使用该设置 Google 会给你一个 refresh_token 并且它会自动存储在 extra_data.

只需在您的 settings.py 中提供:

SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = { 'access_type': 'offline', 'hd': 'xyzabc.com', 'approval_prompt':'force' } 请记住,{'approval_prompt' : 'force'} 会强制用户 select gmail 帐户,这样您将获得刷新令牌。

您可以使用变量向 OAuth2 提供商发送额外参数

SOCIAL_AUTH_<PROVIDER>_AUTH_EXTRA_ARGUMENTS

对于Google,你可以看到他们接受的额外参数in their documentation (scroll down to "parameters")。我们要找的是 access_type:

access_type: Indicates whether your application can refresh access tokens when the user is not present at the browser. Valid parameter values are online, which is the default value, and offline.

所以我们可以在 settings.py 中添加以下内容,以表明我们想要接收刷新令牌:

SOCIAL_AUTH_GOOGLE_OAUTH2_EXTRA_ARGUMENTS = {"access_type: offline"}

EXTRA_ARGUMENTS 的结果将存储在 extra_data 中,因此可以像这样访问刷新令牌:

refresh_token = user.social_auth.get(provider="google-oauth2").extra_data["refresh_token"]

一种可能的解决方案是通过向社交身份验证管道添加自定义函数,将刷新令牌与用户一起存储在 UserProfile 模型中:

  1. 创建模型
# models.py

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
    refresh_token = models.CharField(max_length=255, default="")
  1. 添加一个函数来访问存储刷新令牌
# pipeline.py

from .models import UserProfile

def store_refresh_token(user=none, *args, **kwargs):
    extra_data = user.social_auth.get(provider="google-oauth2").extra_data
    UserProfile.objects.get_or_create(
        user=user, defaults={"refresh_token": extra_data["refresh_token"]}
    )
  1. 将我们的新功能添加到社交身份验证管道中。
# settings.py

...

SOCIAL_AUTH_PIPELINE = (
    ...
    "my-app.pipeline.store_refresh_token"
)  

SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [
    'https://www.googleapis.com/auth/spreadsheets'
    # any other scopes you need
]

...

令牌现在与用户一起存储,可用于初始化工作表客户端或您需要的任何其他内容。