Django视图调用Google Sheets API遇OAuth2 400重定向URI不匹配错误
解决Django对接Google Sheets API的redirect_uri_mismatch问题
这个问题我之前踩过坑,核心原因其实是你用的Google官方快速入门代码里的run_local_server()方法,根本不是为Django这类Web框架设计的——它会偷偷启动一个临时的本地HTTP服务器来处理OAuth2的授权回调,默认情况下会随机挑一个可用的端口(就是你看到的65262这种),哪怕你设了port=0,系统还是会自动分配随机端口,这和你Django服务用的8000端口完全是两个独立的东西,自然就和API控制台里设置的回调URI不匹配了。
解决步骤
1. 调整Google API控制台的回调URI
先去Google API控制台,把你的授权回调URI改成Django服务的回调地址,比如:http://127.0.0.1:8000/google-oauth-callback/
(如果是生产环境,记得换成你域名对应的HTTPS地址)
2. 修改Django视图代码,抛弃临时服务器
不要用run_local_server()了,手动处理OAuth2的授权流程,让回调直接指向你的Django视图:
第一步:添加回调URL路由
在你的urls.py里加一条路由:
path('google-oauth-callback/', views.google_oauth_callback, name='google_oauth_callback'),
第二步:修改授权视图和回调视图
把原来依赖run_local_server()的代码替换成下面的逻辑:
from google_auth_oauthlib.flow import Flow from django.http import HttpResponseRedirect, HttpResponse from django.conf import settings # Google Sheets API的权限范围,根据你的需求调整 SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly'] def sheets_auth_init(request): # 构建OAuth2流程,指定回调URI为我们刚加的Django路由 flow = Flow.from_client_secrets_file( 'credentials.json', # 你的Google凭证文件路径 scopes=SCOPES, redirect_uri='http://127.0.0.1:8000/google-oauth-callback/' ) # 生成授权URL,同时开启离线访问模式(获取refresh_token) authorization_url, state = flow.authorization_url( access_type='offline', include_granted_scopes='true' ) # 把state存到session里,回调时用来验证请求合法性 request.session['oauth_state'] = state # 重定向到Google的授权页面 return HttpResponseRedirect(authorization_url) def google_oauth_callback(request): # 从session取出之前存的state saved_state = request.session.get('oauth_state') if not saved_state: return HttpResponse("授权请求无效,请重新发起", status=400) # 重新构建flow,传入state和回调URI flow = Flow.from_client_secrets_file( 'credentials.json', scopes=SCOPES, state=saved_state, redirect_uri='http://127.0.0.1:8000/google-oauth-callback/' ) # 用授权码交换访问令牌 flow.fetch_token(authorization_response=request.build_absolute_uri()) # 拿到凭证后,你可以把它存在session、数据库或者缓存里 creds = flow.credentials request.session['sheets_creds'] = { 'token': creds.token, 'refresh_token': creds.refresh_token, 'token_uri': creds.token_uri, 'client_id': creds.client_id, 'client_secret': creds.client_secret, 'scopes': creds.scopes } # 这里可以跳转到你的业务页面,或者直接返回成功提示 return HttpResponse("授权成功!现在可以访问Google Sheets数据了")
3. 后续使用凭证调用API
之后你需要调用Google Sheets API的时候,就从session里取出凭证,重新构建Credentials对象:
from google.oauth2.credentials import Credentials def get_sheets_data(request): creds_data = request.session.get('sheets_creds') if not creds_data: return HttpResponseRedirect('/sheets-auth-init/') creds = Credentials.from_authorized_user_info(creds_data) # 这里就可以用creds调用Google Sheets API了,比如: # service = build('sheets', 'v4', credentials=creds) # ......
额外注意事项
- 开发环境下用
127.0.0.1或者localhost都可以,但要确保API控制台里的回调URI和代码里的完全一致(包括端口和路径) - 生产环境一定要用HTTPS,Google OAuth2不允许非HTTPS的回调(除了本地开发的
127.0.0.1/localhost) credentials.json要妥善保存,不要提交到Git等版本控制系统里,可以用Django的settings来管理路径
内容的提问来源于stack exchange,提问作者darkhorse
相关产品推荐
相关产品推荐

