# Cockpit API auth without a login page
Type: grilling Status: resolved Labels: wayfinder:grilling Blocked by: None
已关闭。Q1–Q5 全部确认。凭据由部署层注入请求头;401 只标相关分区为数据不可用;默认 mock;WebSocket 先 authenticate 再 cockpitSubscribe。
来源:E:\pipe-ner-server\pipe-network-service。
SessionCreationPolicy.STATELESS,CSRF 已禁用。TokenService.getToken() 只从请求头读取,头名由 bootstrap.yaml 的 token.header 给出,值为 Authorization;Bearer 前缀会被剥离。SecurityConfig 的 permitAll 只含 /login、/register、/captchaImage、/**/visualization/**、/ws/deviceStatus,其余 .anyRequest().authenticated()。因此 /api/cockpit/v1/** 必须带 token。/api/cockpit/** 命中 CockpitAuthenticationEntryPoint,返回 HTTP 401,body 为 AjaxResult(code=401, msg="驾驶舱接口需要认证", data=CockpitErrorPayload{category=UNAUTHORIZED, requestId, serverTime})。POST /login 能签发 token;驾驶舱首期不做登录页,所以 token 必须由外部提供。/ws/deviceStatus 握手层是 permitAll;客户端可发 {"type":"authenticate","token":"..."} 完成 JWT/Redis 校验;而 handleCockpitSubscribe 当前只校验 scope,不校验身份,所以 cockpitSubscribe 今天无需 token 即可订阅。ResourcesConfig.corsFilter() 设 addAllowedOriginPattern("*") 并允许全部头与方法,但未开启 allowCredentials。因此跨域 Cookie 会话不可行,请求头方案可行。事实面结论:REST 必须带 Authorization: Bearer <JWT>;token 只能由 /login 签发;驾驶舱没有登录页,所以凭据只能由部署层提供。跨域 Cookie 不可行。
驾驶舱专用接口要求 isAuthenticated(),但首期明确不做登录页。mock 和真实联调分别怎么拿到凭据,失败时又如何只显示数据不可用?
候选:
约束:前端不硬编码账号或密钥;缺失凭据时显示数据不可用,不跳登录页。
凭据承载(Q4=A): 部署层把 Authorization: Bearer <JWT> 注入到发往后端 /api/cockpit/v1/** 的请求:生产由网关/反向代理在转发时补头;开发环境用同一机制的本地反代或部署配置提供的只读 token。适配层统一附加请求头,页面与 store 不触碰 token,前端不保存账号密码、不建登录页。不采用前端内置固定 token。Cookie 会话不可行(后端 CORS 未开 allowCredentials)。
未认证体验(Q1=A): 收到 401 或其他凭据类失败时,只把受影响的数据分区标为「数据不可用」,保留已成功分区与地图骨架;不跳登录页、不整页遮罩、不静默显示空数据。顶部显示一次性数据不可用提示。
默认数据源(Q2=A): 默认走契约化 mock;真实接口必须在部署配置里显式开启(mock/real 走同一适配层,切换只改配置)。
轮询(Q3=A): WebSocket 失败降级轮询与新鲜度语义不在本票定义,归实现票 16。
WebSocket 鉴权(Q5=A): 连接 /ws/deviceStatus 后、发送 cockpitSubscribe 前先发 {"type":"authenticate","token":"..."},token 与 REST 同源。后端当前 cockpitSubscribe 只校验 scope 不校验身份,authenticate 是为后端日后收紧时的前向兼容。鉴权失败只把状态推送标为不可用,REST 快照照常显示。