Skip to main content

前端鉴权 Header 规范(WebUI 内部打开)

前端发送后端请求时,必须读取当前网站 cookie。

必须读取的 cookie:

TMSESSNAME
X-Csrf-Token

请求 header 必须包含:

X-Csrf-Token: <从 cookie 读取到的 X-Csrf-Token 值>
Cookie: TMSESSNAME=<从 cookie 读取到的 TMSESSNAME 值>; X-Csrf-Token=<从 cookie 读取到的 X-Csrf-Token 值>;

示例:

X-Csrf-Token: ltRoTGSICC68drxbvljhBeD2DZ7LPcge
Cookie: TMSESSNAME=46958db9-1f8a-4686-b340-34fd8ccf62e8; X-Csrf-Token=ltRoTGSICC68drxbvljhBeD2DZ7LPcge;

前端实现示例:

function getCookie(name) {
const prefix = encodeURIComponent(name) + "=";
return document.cookie
.split(";")
.map((item) => item.trim())
.find((item) => item.startsWith(prefix))
?.slice(prefix.length) || "";
}

const sessionName = getCookie("TMSESSNAME");
const csrfToken = getCookie("X-Csrf-Token");

const headers = {
"Content-Type": "application/json",
"X-Csrf-Token": csrfToken,
"Cookie": `TMSESSNAME=${sessionName}; X-Csrf-Token=${csrfToken};`
};
注意事项
  1. 浏览器不允许前端手动设置标准 Cookie header。
  2. 本规范使用自定义 header Cookie 传递拼接后的 cookie 字符串。
  3. Cookie 为固定 key 名称,必须按平台要求拼写。
  4. 请求应保留 credentials: "include"

后端如需支持浏览器预检请求,应允许以下 header:

Content-Type
X-Csrf-Token
Cookie

Cookie Header 命名说明: 自定义 header 名称 Cookie 是平台内部命名约定。它绕过了浏览器在 JavaScript fetch/XHR 请求中设置标准 Set-Cookie header 的限制。此名称固定,不得修改 — 任何偏差都会破坏鉴权。

后端鉴权校验示例(Python):

def validate_auth(headers):
'''校验来自前端请求的 Cookie 鉴权 header。'''
cookie_str = headers.get('Cookie', '')
csrf_token = headers.get('X-Csrf-Token', '')

# 解析 Cookie header(格式:key1=val1; key2=val2)
parts = {}
for part in cookie_str.split(';'):
if '=' in part:
k, v = part.strip().split('=', 1)
parts[k.strip()] = v.strip()

session_name = parts.get('TMSESSNAME', '')
cookie_csrf = parts.get('X-Csrf-Token', '')

if not session_name or not csrf_token:
return False
if csrf_token != cookie_csrf:
return False
# 通过 TOS 平台验证会话
return True

后端鉴权校验示例(Go):

func validateAuth(r *http.Request) bool {
cookieStr := r.Header.Get("Cookie")
csrfToken := r.Header.Get("X-Csrf-Token")
if cookieStr == "" || csrfToken == "" {
return false
}
for _, part := range strings.Split(cookieStr, ";") {
kv := strings.SplitN(strings.TrimSpace(part), "=", 2)
if len(kv) == 2 && kv[0] == "X-Csrf-Token" {
if kv[1] != csrfToken {
return false
}
}
}
return true
}

Token 过期与会话失效处理:

  • 鉴权 token 过期或会话失效时,后端必须返回 HTTP 401 Unauthorized
  • 前端必须检测 401 响应并重定向到 TOS 登录页面
  • 请勿尝试自动刷新 token;重定向到 / 触发 TOS 重新鉴权
fetch('/v2/proxy/myapp/api', { credentials: 'include' })
.then(res => {
if (res.status === 401) {
window.location.href = '/'; // 重定向到 TOS 登录
}
return res.json();
});