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
相关产品推荐
相关产品推荐

