尝试从 Django 视图将 OAuth2 与 Google Sheets 结合使用时出现错误 400:redirect_uri_mismatch

dar*_*rse 6 python django google-api google-oauth google-sheets-api

我正在尝试从 Django 视图连接到 Google Sheets 的 API。我从此链接中获取的大部分代码: https ://developers.google.com/sheets/api/quickstart/python

无论如何,这里是代码:

sheets.py(从上面的链接复制粘贴,函数重命名)

from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']

# The ID and range of a sample spreadsheet.
SAMPLE_SPREADSHEET_ID = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms'
SAMPLE_RANGE_NAME = 'Class Data!A2:E'

def test():
    """Shows basic usage of the Sheets API.
    Prints values from a sample spreadsheet.
    """
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    service = build('sheets', 'v4', credentials=creds)

    # Call the Sheets API
    sheet = service.spreadsheets()
    result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
                                range=SAMPLE_RANGE_NAME).execute()
    values = result.get('values', [])

    if not values:
        print('No data found.')
    else:
        print('Name, Major:')
        for row in values:
            # Print columns A and E, which correspond to indices 0 and 4.
            print('%s, %s' % (row[0], row[4]))
Run Code Online (Sandbox Code Playgroud)

urls.py

urlpatterns = [
    path('', views.index, name='index')
]
Run Code Online (Sandbox Code Playgroud)

视图.py

from django.http import HttpResponse
from django.shortcuts import render

from .sheets import test

# Views

def index(request):
    test()
    return HttpResponse('Hello world')
Run Code Online (Sandbox Code Playgroud)

视图函数所做的只是调用sheets.pytest()模块中的方法。无论如何,当我运行服务器并访问 URL 时,会打开另一个用于 Google oAuth2 的选项卡,这意味着已检测到凭据文件以及所有内容。但是,在此选项卡中,Google 显示以下错误消息:

Error 400: redirect_uri_mismatch The redirect URI in the request, http://localhost:65262/, does not match the ones authorized for the OAuth client.
Run Code Online (Sandbox Code Playgroud)

在我的 API 控制台中,我将回调 URL 设置为与127.0.0.1:8000我的 Django 视图 URL 完全匹配。我什至不知道在哪里http://localhost:65262/网址是从哪里来的。有帮助解决这个问题吗?有人可以向我解释为什么会发生这种情况吗?提前致谢。

编辑 我尝试删除port=0注释中提到的 in the flow 方法,然后发生 URL 不匹配http://localhost:8080/,这又很奇怪,因为我的 Django 应用程序正在端口中运行8000

小智 6

我遇到了与redirect_uri错误相同的问题,结果(如上所述)我在谷歌控制台中创建了我的凭据作为类型“Web服务器”而不是“桌面应用程序”。我创建了新的信用作为“桌面应用程序”,下载了 JSON 并且它起作用了。

最终,我想将 GMAIL API 用于 Web 服务器,但这与示例的流程不同。


Olu*_*ule 5

除非您无意部署代码,否则不应使用Flow.run_local_server() 。这是因为run_local_server在服务器上启动浏览器来完成流程。

如果您自己在本地开发项目,那么这种方法就很好用。

如果您打算使用本地服务器来协商 OAuth 流程。您的机密中配置的重定向 URI 必须与主机的本地服务器默认值匹配localhost,端口为8080

如果您希望部署代码,则必须通过用户浏览器、您的服务器和 Google 之间的交换来执行流程。

由于您已经运行了 Django 服务器,因此您可以使用它来协商流程。

例如,

假设 Django 项目中有一个 tweets 应用程序,其urls.py模块如下。

from django.urls import path, include

from . import views

urlpatterns = [
    path('google_oauth', views.google_oath, name='google_oauth'),
    path('hello', views.say_hello, name='hello'),
]

urls = include(urlpatterns)
Run Code Online (Sandbox Code Playgroud)

您可以为需要凭据的视图实施防护,如下所示。

from django.urls import path, include

from . import views

urlpatterns = [
    path('google_oauth', views.google_oath, name='google_oauth'),
    path('hello', views.say_hello, name='hello'),
]

urls = include(urlpatterns)
Run Code Online (Sandbox Code Playgroud)

请注意,这只是一个示例。如果您决定走这条路,我建议您考虑将 OAuth 流提取到它自己的 Django 应用程序中。