ChatGPT AccessToken 全流程指南与完整实现代码
一、核心内容总结
本文围绕 ChatGPT AccessToken 展开全流程讲解,核心要点如下:
- 本质与价值:AccessToken 是访问 ChatGPT API 的动态身份凭证,具备时效性与细粒度权限控制,相比静态 API Key 更适合多用户第三方应用场景,是 AI 应用认证体系的核心。
- 获取方式选型
- API Key:OpenAI 官方静态密钥,适合个人/内部服务端项目,配置简单但泄露风险高;
- OAuth 2.0(授权码模式):面向公开第三方应用的标准方案,通过用户授权颁发临时 AccessToken + RefreshToken,安全可控,是生产环境推荐方案;
- Session Tokens:模拟浏览器登录的非官方方案,稳定性差,不推荐生产使用。
- OAuth 2.0 完整流程:构造授权 URL → 用户同意授权获取授权码(code)→ 授权码交换 AccessToken 与 RefreshToken → 携带令牌调用 API → 令牌过期后用 RefreshToken 自动刷新。
- 安全与管理规范:全链路强制 HTTPS、服务端加密存储令牌、遵循最小权限原则申请 Scope、定期轮换撤销无效令牌、监控异常调用行为。
- 常见避坑点:接口限流处理、CSRF 攻击防护(state 参数校验)、令牌格式混淆(Bearer 类型)、回调地址与平台配置不一致、缺失自动刷新机制导致服务中断。
二、完整 AccessToken 获取与管理代码(Python + Flask 实现)
基于 OAuth 2.0 授权码模式实现全流程,包含授权跳转、令牌交换、自动刷新、API 调用、缓存管理功能。
2.1 依赖安装
pip install flask requests python-dotenv redis
2.2 完整实现代码
import os
import time
import urllib.parse
import requests
from flask import Flask, request, redirect, session, jsonify
from dotenv import load_dotenv
import redis
# 加载环境变量(生产环境建议使用密钥管理服务)
load_dotenv()
app = Flask(__name__)
app.secret_key = os.getenv("FLASK_SECRET_KEY", "your_random_secret_key_here")
# ====================== 配置项(请替换为自己的配置) ======================
CLIENT_ID = os.getenv("OPENAI_CLIENT_ID")
CLIENT_SECRET = os.getenv("OPENAI_CLIENT_SECRET")
REDIRECT_URI = os.getenv("REDIRECT_URI", "http://localhost:5000/callback")
# 权限范围,根据实际需求调整
SCOPE = "openid profile offline_access"
# OpenAI OAuth 端点
AUTH_URL = "https://auth.openai.com/oauth/authorize"
TOKEN_URL = "https://auth.openai.com/oauth/token"
API_URL = "https://api.openai.com/v1/chat/completions"
# Redis 缓存配置(生产环境用,本地可注释改用内存)
# redis_client = redis.Redis(host='localhost', port=6379, db=0)
# 本地调试用内存缓存
token_cache = {}
# ====================== 核心工具函数 ======================
def generate_csrf_state() -> str:
"""生成随机 state 字符串,用于防 CSRF 攻击"""
import secrets
return secrets.token_urlsafe(32)
def exchange_code_for_token(code: str) -> dict:
"""用授权码 code 交换 AccessToken 和 RefreshToken"""
data = {
"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
response = requests.post(TOKEN_URL, data=data)
response.raise_for_status()
return response.json()
def refresh_access_token(refresh_token: str) -> dict:
"""用 RefreshToken 刷新获取新的 AccessToken"""
data = {
"grant_type": "refresh_token",
"refresh_token": refresh_token,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
response = requests.post(TOKEN_URL, data=data)
response.raise_for_status()
return response.json()
def get_valid_access_token(user_id: str) -> str:
"""
获取有效的 AccessToken
若即将过期(剩余有效期<5分钟)则自动刷新
"""
# 从缓存读取令牌信息
token_info = token_cache.get(user_id)
if not token_info:
raise Exception("用户未授权,请先登录授权")
# 检查是否即将过期
expires_at = token_info["expires_at"]
if time.time() > expires_at - 300: # 提前5分钟刷新
new_token_info = refresh_access_token(token_info["refresh_token"])
# 更新缓存
token_info["access_token"] = new_token_info["access_token"]
token_info["expires_at"] = time.time() + new_token_info.get("expires_in", 3600)
if "refresh_token" in new_token_info:
token_info["refresh_token"] = new_token_info["refresh_token"]
token_cache[user_id] = token_info
return token_info["access_token"]
def call_chatgpt_api(access_token: str, prompt: str) -> dict:
"""携带 AccessToken 调用 ChatGPT 对话接口"""
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
data = {
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": prompt}]
}
response = requests.post(API_URL, headers=headers, json=data)
response.raise_for_status()
return response.json()
# ====================== 路由接口 ======================
@app.route("/login")
def login():
"""第一步:引导用户跳转到 OpenAI 授权页面"""
state = generate_csrf_state()
session["oauth_state"] = state # 存入 session 用于回调校验
params = {
"response_type": "code",
"client_id": CLIENT_ID,
"redirect_uri": REDIRECT_URI,
"scope": SCOPE,
"state": state
}
auth_redirect_url = f"{AUTH_URL}?{urllib.parse.urlencode(params)}"
return redirect(auth_redirect_url)
@app.route("/callback")
def oauth_callback():
"""第二步:接收授权回调,交换令牌并存储"""
# 校验 state,防止 CSRF
received_state = request.args.get("state")
if received_state != session.get("oauth_state"):
return jsonify({"error": "State 校验失败,可能存在 CSRF 攻击"}), 400
code = request.args.get("code")
if not code:
return jsonify({"error": "未获取到授权码"}), 400
try:
# 交换令牌
token_data = exchange_code_for_token(code)
# 计算过期时间戳
token_data["expires_at"] = time.time() + token_data.get("expires_in", 3600)
# 存储令牌(示例用 user_id=1,实际项目关联真实用户ID)
user_id = "user_1"
token_cache[user_id] = {
"access_token": token_data["access_token"],
"refresh_token": token_data.get("refresh_token", ""),
"expires_at": token_data["expires_at"]
}
return jsonify({
"message": "授权成功,AccessToken 已获取并缓存",
"expires_in": token_data.get("expires_in"),
"expires_at": token_data["expires_at"]
})
except Exception as e:
return jsonify({"error": f"令牌交换失败: {str(e)}"}), 500
@app.route("/chat")
def chat():
"""第三步:使用有效令牌调用 ChatGPT API"""
prompt = request.args.get("prompt", "你好,请介绍一下自己")
user_id = "user_1"
try:
access_token = get_valid_access_token(user_id)
result = call_chatgpt_api(access_token, prompt)
return jsonify({
"reply": result["choices"][0]["message"]["content"],
"usage": result["usage"]
})
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route("/refresh")
def manual_refresh():
"""手动刷新令牌接口(调试用)"""
user_id = "user_1"
try:
token_info = token_cache.get(user_id)
if not token_info or not token_info.get("refresh_token"):
return jsonify({"error": "无可用的 RefreshToken"}), 400
new_token = refresh_access_token(token_info["refresh_token"])
token_info["access_token"] = new_token["access_token"]
token_info["expires_at"] = time.time() + new_token.get("expires_in", 3600)
token_cache[user_id] = token_info
return jsonify({"message": "刷新成功", "new_expires_at": token_info["expires_at"]})
except Exception as e:
return jsonify({"error": f"刷新失败: {str(e)}"}), 500
if __name__ == "__main__":
# 本地运行,生产环境请使用 WSGI 服务器并启用 HTTPS
app.run(host="0.0.0.0", port=5000, debug=True)
2.3 环境变量配置(.env 文件)
在项目根目录创建 .env 文件,填入 OAuth 应用对应信息:
OPENAI_CLIENT_ID=你的client_id
OPENAI_CLIENT_SECRET=你的client_secret
REDIRECT_URI=http://localhost:5000/callback
FLASK_SECRET_KEY=自定义随机字符串
三、使用步骤与安全说明
3.1 前置准备
前往 OpenAI 开发者平台注册 OAuth 应用,获取 client_id 和 client_secret,并将 http://localhost:5000/callback 添加到授权回调地址白名单。
3.2 运行流程
- 启动程序后,访问
http://localhost:5000/login跳转授权页面; - 授权成功后自动回调,完成令牌交换与缓存存储;
- 访问
http://localhost:5000/chat?prompt=你的问题测试 API 调用效果。
3.3 生产环境安全建议
- 所有接口必须启用 HTTPS,禁止明文传输令牌信息;
- 禁止硬编码密钥,使用环境变量或专业密钥管理服务(如 AWS Secrets Manager、HashiCorp Vault);
- RefreshToken 需加密后存入数据库,AccessToken 优先使用 Redis 缓存并设置合理过期时间;
- 增加接口限流、异常调用监控与令牌撤销机制;
- 本地调试的
localhost回调地址仅用于开发,生产环境需替换为正式域名。