You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python对接Google OAuth2报错:Token段数错误问题排查

解决Flask API对接时OAuth2令牌段数错误的问题

嘿,这个坑我之前踩过!你遇到的Wrong number of segments in token错误,根源其实很简单:你硬编码的ya29.xxx开头的令牌是Google的OAuth2访问令牌,它不是标准的JWT格式,而Flask默认的OAuth2验证逻辑是按照JWT的三段式(header.payload.signature)来解析令牌的,自然就会报“段数不对”的错啦。

错误原因拆解

Google的OAuth2访问令牌(ya29开头)属于不透明令牌,它没有JWT那种用点.分隔的三段结构,只是Google内部识别的一串字符。当Flask的OAuth2库(比如authlibflask-oauthlib)尝试把它当作JWT解析时,自然会因为格式不匹配抛出错误。

针对性解决方案

情况1:你需要验证Google的OAuth2令牌

如果你的业务是让用户通过Google登录,然后把Google的访问令牌传给Flask服务器验证,那不能用本地的JWT解析逻辑,而是要调用Google官方的令牌验证接口来校验:

import requests
from flask import jsonify, request

@app.route('/your-protected-endpoint')
def protected_endpoint():
    # 从请求头获取Bearer令牌
    auth_header = request.headers.get('Authorization')
    if not auth_header or not auth_header.startswith('Bearer '):
        return jsonify({"error": "请提供有效的Bearer令牌"}), 401
    
    token = auth_header.split(' ')[1]
    # 调用Google令牌验证接口
    verify_url = f"https://oauth2.googleapis.com/tokeninfo?access_token={token}"
    response = requests.get(verify_url)
    
    if response.status_code == 200:
        token_info = response.json()
        # 可额外验证令牌的受众是否匹配你的Google客户端ID
        if token_info.get('aud') == "你的Google客户端ID":
            return jsonify({"message": "令牌验证通过", "user_info": token_info})
        else:
            return jsonify({"error": "令牌受众不匹配"}), 401
    else:
        return jsonify({"error": "无效的令牌"}), 401

情况2:你想让Flask自己生成/验证JWT令牌

如果你的OAuth2体系是自主搭建的,不需要依赖Google的令牌,那应该生成标准的JWT格式令牌,用PyJWT库来处理:

首先安装依赖:

pip install pyjwt

然后编写生成和验证逻辑:

import jwt
from datetime import datetime, timedelta
from flask import jsonify, request

# 替换为你的密钥,生产环境建议存到环境变量中
SECRET_KEY = "your-strong-secret-key-here"

# 生成JWT令牌
def generate_jwt(user_id):
    payload = {
        "user_id": user_id,
        "exp": datetime.utcnow() + timedelta(hours=1)  # 令牌1小时后过期
    }
    return jwt.encode(payload, SECRET_KEY, algorithm="HS256")

# 验证JWT令牌
def verify_jwt(token):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        return payload
    except jwt.ExpiredSignatureError:
        return None  # 令牌过期
    except jwt.InvalidTokenError:
        return None  # 令牌无效

@app.route('/login')
def login():
    # 模拟用户登录验证,验证通过后生成令牌
    user_id = "12345"
    token = generate_jwt(user_id)
    return jsonify({"access_token": token})

@app.route('/protected')
def protected():
    auth_header = request.headers.get('Authorization')
    if not auth_header or not auth_header.startswith('Bearer '):
        return jsonify({"error": "缺少有效授权头"}), 401
    
    token = auth_header.split(' ')[1]
    payload = verify_jwt(token)
    if payload:
        return jsonify({"message": "访问成功", "user_id": payload["user_id"]})
    else:
        return jsonify({"error": "令牌无效或已过期"}), 401

额外提示

如果你用authlib这类OAuth2库对接Google,一定要确保配置的是Google专属的OAuth2流程:正确设置客户端ID、客户端密钥,以及Google的授权端点和令牌端点,不要硬编码令牌让库去解析。

内容的提问来源于stack exchange,提问作者Mikhail Krassavin

火山引擎 最新活动