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

OAuth授权流程中跨请求共享session_id的技术问题

解决OAuth令牌关联用户时Session ID无法获取的问题

问题核心

你当前的流程里,外部API重定向到客户端后,由客户端将code传给服务端的/callback端点。此时服务端的/callback要么接收的是客户端请求但客户端没传递session_id,要么是外部API直接调用该端点(外部API不会携带客户端Cookie),导致request.cookies为空,无法拿到session_id关联令牌和用户。

解决方案

方案1:遵循标准OAuth流程,让外部API直接重定向到服务端/callback

这是最规范的做法,浏览器在重定向到服务端/callback时,会自动携带同域下的session_id Cookie(需确保Cookie属性设置正确)。

代码修改步骤:

  1. 在/login端点的授权URL参数中添加redirect_uri,指向服务端的/callback:
@app.get("/login")
async def login(request: Request, response: Response, db: Session = Depends(get_db)):
    params = {
        "client_id": CLIENT_ID,
        "scope": SCOPE,
        "code_challenge": create_code_challenge(app.state.verifier),
        "code_challenge_method": "S256",
        "response_type": "code",
        # 添加重定向地址为服务端的callback,需与OAuth平台注册的地址完全一致
        "redirect_uri": "http://你的服务端域名/callback"
    }
    res = requests.get(f"{AUTH_URL}", params=params)
    session_id = str(uuid.uuid4())
    # 设置Cookie安全属性,确保重定向时能被浏览器携带
    response.set_cookie(
        key="session_id", 
        value=session_id, 
        httponly=True, 
        secure=True, 
        samesite="Lax"
    )
    return {"url": res.url}
  1. 调整/callback端点,确保能正常获取session_id:
@app.get("/callback")
async def callback(code, request: Request, db: Session = Depends(get_db)) -> None:
    params = {
        "client_id": CLIENT_ID,
        "code": code,
        "code_verifier": app.state.verifier,
        "grant_type": "authorization_code",
        # 必须和login中设置的redirect_uri完全一致
        "redirect_uri": "http://你的服务端域名/callback"
    }
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    res = requests.post(
        TOKEN_URL,
        auth=HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET),
        data=params,  # 用data传递参数,符合application/x-www-form-urlencoded格式要求
        headers=headers,
    )
    token = json.loads(res.content)
    # 现在可正常从Cookie中获取session_id
    token["session_id"] = request.cookies["session_id"]

    db_token = models.Token(**token)
    db.add(db_token)
    db.commit()
    db.refresh(db_token)

    # 完成后可重定向回客户端
    return RedirectResponse(url="http://你的客户端域名")

方案2:客户端主动传递Session ID给服务端/callback

如果必须保留“外部API先重定向到客户端,再由客户端传code给服务端”的流程,需要让客户端在请求服务端/callback时,主动携带session_id。

代码修改步骤:

  1. 客户端拿到code后,从Cookie中取出session_id,一起传给服务端/callback(示例为浏览器端JS):
const code = new URLSearchParams(window.location.search).get('code');
const sessionId = document.cookie.split('; ').find(row => row.startsWith('session_id=')).split('=')[1];
fetch(`http://你的服务端域名/callback?code=${code}&session_id=${sessionId}`);
  1. 服务端/callback接收session_id参数:
@app.get("/callback")
async def callback(code, session_id: str, db: Session = Depends(get_db)) -> None:
    params = {
        "client_id": CLIENT_ID,
        "code": code,
        "code_verifier": app.state.verifier,
        "grant_type": "authorization_code",
    }
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    res = requests.post(
        TOKEN_URL,
        auth=HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET),
        data=params,
        headers=headers,
    )
    token = json.loads(res.content)
    token["session_id"] = session_id

    db_token = models.Token(**token)
    db.add(db_token)
    db.commit()
    db.refresh(db_token)

    return

注意事项

  • 方案1中,redirect_uri必须和你在外部OAuth平台注册的回调地址完全一致,否则会触发授权错误。
  • 设置Cookie时,httponly=True可防止XSS攻击窃取Cookie,secure=True要求HTTPS传输,samesite="Lax"确保跨站重定向时Cookie能被正常携带。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:52:57