Skip to content

部署与安全

上线前要定三件事:谁能嵌谁能看数据到哪为止

允许哪些宿主嵌

报表服务的配置文件 conch.config.json

json
{
  "embed": {
    "allowedOrigins": ["https://hdms.example.com", "https://portal.example.com"]
  }
}

配了这一段,报表服务在每个响应上发 Content-Security-Policy: frame-ancestors https://hdms.example.com https://portal.example.com——只有这两个站点能把报表嵌进 iframe,别人嵌会被浏览器挡掉。

不配这一段就不发这个头,任何站点都能嵌。本地开发和演示可以不配,正式部署应当配上。改完重启报表服务生效。

也要检查反向代理

有些网关默认往回加 X-Frame-Options: SAMEORIGIN,那一条会让所有跨域嵌入失败,而且比 frame-ancestors 更粗暴。报表服务自己不发这个头,发了就是代理加的,去代理上关掉。

谁能看到报表

这一版的查看页没有自己的登录页。 访问控制靠部署位置来做,两种可行方案:

一、放在内网 / 只开给宿主的网络 报表服务不暴露到公网,只有能访问宿主系统的人能访问它。最省事,适合院内、厂内部署。

二、由宿主反向代理,鉴权在代理上做 把报表服务挂到宿主自己的域名下,用户的登录态(cookie)天然带上,也没有跨站 cookie 的麻烦:

nginx
location /report/ {
    # 这里接你们自己的鉴权(auth_request / JWT 校验 / 基础认证)
    auth_request /your-auth;

    proxy_pass http://127.0.0.1:5088/;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    # 多租户部署时由代理钉死租户,浏览器改不了
    proxy_set_header X-Conch-Tenant hospital-a;

    # 对话式生成走 SSE,必须关缓冲
    proxy_buffering off;
}

宿主页面里 iframe 就写 src="/report/?id=...&view=1",同源,frame-ancestors 也不用配了。

别把报表服务直接开到公网又不设任何认证

查看态链接里只有报表 id,能猜到 id 的人就能看到那张报表的数据。公网部署一定要在前面加一道认证。

租户目前从请求头 X-Conch-Tenant 取,浏览器发不出这个头,所以多租户必须在反向代理上注入,不能指望前端传。

按登录身份把宿主的科室、区域、角色带进报表(JWT 换票)在路线上,还没上线;现在需要这类隔离的场合,按租户分开部署。

数据边界在哪

这一层做了什么
数据库账号只读账号,写操作在库上就被拒
SQL 守卫报表里的每条 SQL 执行前都过一遍守卫,只放行单条只读查询
查看态下发内容规格里的 SQL 正文不下发到浏览器,查看页拿到的只有渲染要用的结构
客户端传参查看态只报版本号,规格由服务端按那一版取,浏览器传来的规格不作数
行级范围由服务端按调用者身份注入系统参数,SQL 里引用它做过滤
模型只在设计态参与,只看表结构与字典值;运行态没有模型,数据从库到浏览器不经过任何模型

lock= 只是界面口径(控件只读),不是权限。会改链接的人能把它去掉。要做到「这个人只能看到自己那部分数据」,必须落在行级范围参数上,不能靠 lock

HTTPS

宿主是 https://、报表服务是 http://,浏览器会按混合内容直接拦掉 iframe,页面上一片空白。两边都上 HTTPS,或者都走同一个域名下的反向代理。

链接里别放这些

  • 不要放 token、密码、签名。查看态链接会进浏览器历史、进 Referer、被人抄给同事。
  • 不要放 SQL。报表服务不接受从链接或请求体传 SQL 来执行。
  • 不要放能反推出别人身份的值——链接是可以改的,把 dept=A 改成 dept=B 的成本是零。

版本怎么发才稳

  • 嵌出去的链接默认跟着当前发布版走。设计者改草稿不会影响生产页面,重新发布才会更新
  • 要在改版期间保持页面不变,把链接钉在某一版:&version=v3
  • 要给客户一份不会再变的数,发布时选「数据快照」,那一版打开不查库。
  • version=draft 只用于发布前自查,别出现在给客户的链接里。

给 AI 用的纯文本索引在 /llms.txt,每篇原文在 /md/ 下。