You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker容器中Flask应用对接YouTube OAuth遇State不匹配错误的解决

问题:Docker部署Flask应用时Google OAuth授权出现State不匹配错误

我正在开发一个基于Flask后端的网站,用于向YouTube上传视频。本地运行Web服务器时,已完成配额申请且能正常上传视频,但部署到Docker容器后,即使在Google控制台将重定向URI设置为https://vod.mydomain.dev/oauth2callback并调整了代码中的OAuth配置,仍始终遇到以下错误:

oauthlib.oauth2.rfc6749.errors.MismatchingStateError: (mismatching_state) CSRF Warning! State not equal in request and response.

想请教如何在Docker容器部署的网页中通过OAuth完成Google授权?

以下是我的代码:

import os
import google.oauth2.credentials
import google_auth_oauthlib.flow
from googleapiclient.errors import HttpError
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload

from flask import Flask, request, redirect, session, url_for

app = Flask(__name__)
app.secret_key = os.urandom(24)

# Ersetzen Sie YOUR_CLIENT_ID und YOUR_CLIENT_SECRET mit Ihren eigenen Werten
os.environ['GOOGLE_CLIENT_ID'] = 
os.environ['GOOGLE_CLIENT_SECRET'] = 
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

CLIENT_SECRETS_FILE = "client_secret.json"
SCOPES = ['https://www.googleapis.com/auth/youtube.upload']


@app.route('/')
def index():
    return 'Hello World! <a href="/authorize">Authorize</a> '+ url_for('oauth2callback', _external=True, _scheme='https')
    

@app.route('/authorize')
def authorize():
    flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
        CLIENT_SECRETS_FILE, scopes=SCOPES)
    flow.redirect_uri = url_for('oauth2callback', _external=True, _scheme='https')
    authorization_url, state = flow.authorization_url(
        access_type='offline',
        include_granted_scopes='true')

    session['state'] = state
    print(session['state'],flow.redirect_uri)
    return redirect(authorization_url)


@app.route('/oauth2callback')
def oauth2callback():
    state = session['state']

    flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
        CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
    flow.redirect_uri = url_for('oauth2callback', _external=True)

    authorization_response = request.url
    flow.fetch_token(authorization_response=authorization_response)

    credentials = flow.credentials
    session['credentials'] = {
        'token': credentials.token,
        'refresh_token': credentials.refresh_token,
        'token_uri': credentials.token_uri,
        'client_id': credentials.client_id,
        'client_secret': credentials.client_secret,
        'scopes': credentials.scopes
    }

    return redirect('/upload_video')


@app.route('/upload_video')
def upload_video():
    if 'credentials' not in session:
        return redirect('authorize')

    credentials = google.oauth2.credentials.Credentials(**session['credentials'])

    try:
        youtube = build('youtube', 'v3', credentials=credentials)

        body = {
            "snippet": {
                "categoryId": "22",
                "description": "Beschreibung des Videos",
                "title": "Funktioniert der Automatische Upload?"
            },
            "status": {
                "privacyStatus": "private"
            }
        }

        video_file = "/clips/Test.mp4"
        media = MediaFileUpload(video_file, mimetype='video/mp4', chunksize=-1, resumable=True)

        request = youtube.videos().insert(
            part=",".join(body.keys()),
            body=body,
            media_body=media
        )

        response = request.execute()
        return f'Video wurde erfolgreich hochgeladen: {response}'

    except HttpError as error:
        return f'Ein Fehler ist aufgetreten: {error}'


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=443)

本地直接运行脚本一切正常,但创建Docker容器后,虽能进入登录界面,但重定向回自有域名时就会出错崩溃。


解决方案

1. 固定Flask Session密钥

Docker容器每次启动时,os.urandom(24)会生成新的随机密钥,导致session无法跨请求保存state值,引发不匹配错误。

  • 修复步骤:
    替换代码中随机生成密钥的逻辑,改用固定密钥(通过环境变量注入更安全):
    # 替换原有的app.secret_key = os.urandom(24)
    app.secret_key = os.environ.get('FLASK_SECRET_KEY', 'your_secure_fixed_secret_key')
    
    启动Docker容器时注入环境变量:
    docker run -e FLASK_SECRET_KEY=your_actual_secure_key ...
    

2. 统一重定向URI的HTTPS协议

oauth2callback函数中生成redirect_uri时未指定_scheme='https',导致生成HTTP地址,与Google控制台配置的HTTPS地址不匹配,影响state验证。

  • 修复步骤:
    修改oauth2callback中的redirect_uri设置:
    flow.redirect_uri = url_for('oauth2callback', _external=True, _scheme='https')
    

3. 移除不安全传输环境变量

生产HTTPS环境下不需要OAUTHLIB_INSECURE_TRANSPORT=1,该变量仅用于本地HTTP测试,开启后会干扰OAuth的安全验证流程。

  • 修复步骤:
    删除或注释掉代码中的这一行:
    # os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
    

4. 配置反向代理的头信息传递

如果使用Nginx等反向代理转发请求到Docker容器,需要确保传递正确的协议和主机头,让Flask能生成正确的外部URL。

  • 示例Nginx配置片段:
    location / {
        proxy_pass http://your_flask_container:443;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
    
    同时在Flask中开启代理支持:
    from werkzeug.middleware.proxy_fix import ProxyFix
    app = Flask(__name__)
    app.config['PREFERRED_URL_SCHEME'] = 'https'
    # 配置代理头,x_proto=1表示信任X-Forwarded-Proto头
    app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
    
    需先安装依赖:pip install werkzeug

5. 验证Google控制台的重定向URI

确保Google Cloud控制台中配置的重定向URI与代码生成的完全一致,检查是否存在拼写错误、多余斜杠或协议不匹配的情况,必须是https://vod.mydomain.dev/oauth2callback。


内容的提问来源于stack exchange,提问作者Marvin S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 21:22:00