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

React跳转Streamlit时如何通过HTTP Header传递BearerToken实现认证

安全传递认证Token至Streamlit的解决方案

浏览器通过window.location.href发起的跳转是标准GET请求,无法自定义HTTP请求头,所以没法直接通过Header传递Bearer Token。以下是几种安全可行的替代方案:


方案一:临时会话Cookie传递

这种方式利用HttpOnly Cookie的安全性,避免Token暴露在URL或前端可访问的存储中:

React端实现

先调用Streamlit服务的专用接口验证Token并设置Cookie,再跳转至Streamlit页面:

fetch('http://streamlit_url/api/set-auth-cookie', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${bearerToken}`,
    'Content-Type': 'application/json'
  }
})
.then(res => {
  if (res.ok) {
    window.location.href = 'http://streamlit_url';
  } else {
    console.error('Token验证失败');
    // 可添加前端提示逻辑
  }
})
.catch(err => console.error('请求出错:', err));

Streamlit端实现

需要扩展一个接口处理Cookie设置(可通过FastAPI与Streamlit结合部署):

from fastapi import FastAPI, Request, Response
from fastapi.middleware.cors import CORSMiddleware
import streamlit as st
from streamlit.web.server.server import Server

app = FastAPI()

# 配置CORS,允许你的React应用域名访问
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://你的React应用域名"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Token验证并设置Cookie的接口
@app.post("/api/set-auth-cookie")
async def set_auth_cookie(request: Request, response: Response):
    auth_header = request.headers.get("Authorization")
    if not auth_header or not auth_header.startswith("Bearer "):
        return {"status": "error", "msg": "无效授权头"}
    
    token = auth_header.split(" ")[1]
    # 替换为你的实际Token验证逻辑(如解析JWT、调用认证服务)
    if validate_token(token):
        # 设置安全Cookie:HttpOnly防XSS,Secure仅HTTPS生效,SameSite防CSRF
        response.set_cookie(
            key="auth_token",
            value=token,
            httponly=True,
            secure=True,  # 生产环境必须开启
            samesite="strict",
            max_age=3600  # 有效期1小时,按需调整
        )
        return {"status": "success"}
    else:
        return {"status": "error", "msg": "Token无效"}

# 挂载Streamlit主应用
@app.get("/")
async def streamlit_main():
    return Server.get_current()._send_request("/", request.scope)

# 示例Token验证函数
def validate_token(token):
    # 实现你的验证逻辑
    return True

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8501)

在Streamlit主页面读取Cookie完成认证:

import streamlit as st

def get_auth_token():
    cookie_header = st.experimental_get_request_header("Cookie")
    if cookie_header:
        cookies = dict(c.split("=") for c in cookie_header.split("; "))
        return cookies.get("auth_token")
    return None

token = get_auth_token()
if not token or not validate_token(token):
    st.error("未授权访问,请先登录")
    st.stop()

# 认证通过,展示业务内容
st.success("认证成功!")
# 后续业务代码...

方案二:隐藏表单POST传递

通过生成隐藏HTML表单,用POST方法提交Token,避免Token出现在URL中:

React端实现

function redirectWithToken(token) {
    const form = document.createElement('form');
    form.method = 'POST';
    form.action = 'http://streamlit_url';
    
    const tokenInput = document.createElement('input');
    tokenInput.type = 'hidden';
    tokenInput.name = 'auth_token';
    tokenInput.value = token;
    
    form.appendChild(tokenInput);
    document.body.appendChild(form);
    form.submit();
}

// 调用跳转
redirectWithToken(bearerToken);

Streamlit端实现

import streamlit as st
from streamlit.web.server.server import Server

def get_post_token():
    req = Server.get_current()._request
    if req.method == "POST":
        return req.form.get("auth_token")
    return None

token = get_post_token()
if not token or not validate_token(token):
    st.error("未授权访问")
    st.stop()

st.success("认证成功!")
# 业务逻辑...

方案三:一次性短码交换

用有效期极短的一次性短码替代Token传递,降低泄露风险:

React端实现

先向你的认证服务申请短码,再携带短码跳转:

fetch('http://你的认证服务地址/api/get-short-code', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${bearerToken}`,
    'Content-Type': 'application/json'
  }
})
.then(res => res.json())
.then(data => {
    if (data.short_code) {
        window.location.href = `http://streamlit_url?code=${data.short_code}`;
    }
})
.catch(err => console.error(err));

Streamlit端实现

用短码向认证服务换取Token:

import streamlit as st
import requests

query_params = st.experimental_get_query_params()
short_code = query_params.get("code", [None])[0]

if not short_code:
    st.error("缺少授权码")
    st.stop()

# 向认证服务换取Token
res = requests.post('http://你的认证服务地址/api/exchange-token', json={"short_code": short_code})
if res.status_code == 200:
    token = res.json().get("bearer_token")
    if token and validate_token(token):
        st.success("认证成功!")
        # 业务逻辑...
    else:
        st.error("无效授权码")
else:
    st.error("授权码验证失败")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:12:16