yudao-cloud 开发指南 yudao-cloud 开发指南
  • 萌新必读
  • 后端手册
  • 微服务手册
  • 工作流手册
  • 大屏手册
  • 支付手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 前端手册 Vue 3.x
  • 前端手册 Vben 5.x
  • 前端手册 Vue 2.x
  • 前端手册 Admin Uniapp
  • 工作流手册
  • 大屏手册
  • 支付手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
视频教程
  • Vue3 + element-plus (opens new window)
  • Vue3 + vben5(ant-design-vue、element-plus) (opens new window)
  • Vue2 + element-ui (opens new window)
单体版 (opens new window)
作者博客 (opens new window)
GitHub (opens new window)
  • 萌新必读
  • 后端手册
  • 微服务手册
  • 工作流手册
  • 大屏手册
  • 支付手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 前端手册 Vue 3.x
  • 前端手册 Vben 5.x
  • 前端手册 Vue 2.x
  • 前端手册 Admin Uniapp
  • 工作流手册
  • 大屏手册
  • 支付手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
视频教程
  • Vue3 + element-plus (opens new window)
  • Vue3 + vben5(ant-design-vue、element-plus) (opens new window)
  • Vue2 + element-ui (opens new window)
单体版 (opens new window)
作者博客 (opens new window)
GitHub (opens new window)
  • 萌新必读

    • 简介
    • 交流群
    • 视频教程
    • 功能列表
    • 快速启动(后端项目)
    • 快速启动(前端项目)
    • 接口文档
    • 技术选型
    • 项目结构
    • 代码热加载
    • 一键改包
    • 迁移模块(适合新项目)
    • 删除功能(以租户为例)
    • 表结构变更(版本升级)
    • 国产信创数据库(DM 达梦、大金、OpenGauss、瀚高、OceanBase、TiDB、GaussDB、PolarDB、神通、Vastbase、MogDB、TongRDS、CacheDB)
    • 面试题、简历模版、简历优化
    • 项目外包
    • 文档 MCP
  • 后端手册

    • 新建服务
    • 代码生成【单表】(新增功能)
    • 代码生成【主子表】
    • 代码生成(树表)
    • 代码生成(移动端)
    • 功能权限
    • 数据权限
    • 用户体系
    • 三方登录
    • OAuth 2.0(SSO 单点登录)
    • SaaS 多租户【字段隔离】
    • SaaS 多租户【数据库隔离】
    • WebSocket 实时通信
    • 异常处理(错误码)
    • 参数校验、时间传参
    • 分页实现
    • VO 对象转换、数据翻译
    • 文件存储(上传下载)
    • Excel 导入导出
    • 操作日志、访问日志、异常日志
    • MyBatis 数据库
    • MyBatis 联表&分页查询
    • 多数据源(读写分离)、事务
    • Redis 缓存
    • 本地缓存
    • 异步任务
    • 分布式锁
    • 幂等性(防重复提交)
    • 请求限流(RateLimiter)
    • HTTP 接口签名(防篡改)
    • HTTP 接口加解密
    • 单元测试
    • 验证码
    • 工具类 Util
    • 数据库文档
  • 微服务手册

    • 微服务调试(必读)
    • 注册中心 Nacos
    • 配置中心 Nacos
    • 服务网关 Spring Cloud Gateway
    • 服务调用 Feign
    • 定时任务 XXL Job
    • 消息队列(内存)
    • 消息队列(Redis)
    • 消息队列(RocketMQ)
    • 消息队列(RabbitMQ)
    • 消息队列(Kafka)
    • 消息队列(Cloud)
    • 分布式事务 Seata
    • 服务保障 Sentinel
    • 分库分表
  • 工作流手册

    • 工作流演示
    • 功能开启
    • 工作流(达梦适配)
    • 审批接入(流程表单)
    • 审批接入(业务表单)
    • 流程设计器(BPMN)
    • 流程设计器(钉钉、飞书)
    • 选择审批人、发起人自选
    • 会签、或签、依次审批
    • 流程发起、取消、重新发起
    • 审批通过、不通过、驳回
    • 审批加签、减签
    • 审批转办、委派、抄送
    • 执行监听器、任务监听器
    • 流程表达式
    • 流程审批通知
    • 移动端审批
  • 大屏手册

    • 报表设计器
    • 大屏设计器
  • 支付手册

    • 功能开启
    • 支付宝支付接入
    • 微信公众号支付接入
    • 微信小程序支付接入
    • 支付宝、微信退款接入
    • 支付宝转账接入
    • 微信转账接入
    • 钱包充值、支付、退款
    • 模拟支付、退款
    • 移动端支付管理
  • 会员手册

    • 功能开启
    • 微信公众号登录
    • 微信小程序登录
    • 微信小程序订阅消息
    • 微信小程序码
    • 会员用户、标签、分组
    • 会员等级、积分、签到
    • 移动端会员管理
  • 商城手册

    • 商城演示
    • 功能开启
    • 商城装修
    • 在线客服
    • 【商品】商品分类
    • 【商品】商品属性
    • 【商品】商品 SPU 与 SKU
    • 【商品】商品评价
    • 【交易】购物车
    • 【交易】交易订单
    • 【交易】售后退款
    • 【交易】快递发货
    • 【交易】门店自提
    • 【交易】分销返佣
    • 【营销】优惠劵
    • 【营销】积分商城
    • 【营销】拼团活动
    • 【营销】秒杀活动
    • 【营销】砍价活动
    • 【营销】满减送活动
    • 【营销】限时折扣
    • 【营销】内容管理
    • 【统计】会员、商品、交易统计
    • 移动端商城管理
  • ERP手册

    • ERP 演示
    • 功能开启
    • 【产品】产品信息、分类、单位
    • 【库存】产品库存、库存明细
    • 【库存】其它入库、其它出库
    • 【库存】库存调拨、库存盘点
    • 【采购】采购订单、入库、退货
    • 【销售】销售订单、出库、退货
    • 【财务】采购付款、销售收款
    • 移动端 ERP
  • CRM手册

    • CRM 演示
    • 功能开启
    • 【线索】线索管理
    • 【客户】客户管理、公海客户
    • 【商机】商机管理、商机状态
    • 【合同】合同管理、合同提醒
    • 【回款】回款管理、回款计划
    • 【产品】产品管理、产品分类
    • 【通用】数据权限
    • 【通用】跟进记录、待办事项
    • 移动端 CRM
  • AI大模型手册

    • AI 大模型演示
    • 功能开启
    • AI 聊天对话
    • AI 绘画创作
    • AI 知识库(RAG)
    • AI 音乐创作
    • AI 写作助手
    • AI 思维导图
    • AI 工具(function calling)
    • AI 工作流
    • Dify 工作流
    • FastGPT 工作流
    • Coze 智能体
    • 推理模式(thinking)
    • 联网搜索
    • MCP Client 客户端
    • MCP Server 服务端
    • 【模型接入】Claude
    • 【模型接入】OpenAI
    • 【模型接入】通义千问
    • 【模型接入】DeepSeek
    • 【模型接入】字节豆包
    • 【模型接入】腾讯混元
    • 【模型接入】硅基流动
    • 【模型接入】MiniMax
    • 【模型接入】月之暗面
    • 【模型接入】百川智能
    • 【模型接入】文心一言
    • 【模型接入】LLAMA
    • 【模型接入】智谱 GLM
    • 【模型接入】讯飞星火
    • 【模型接入】微软 OpenAI
    • 【模型接入】谷歌 Gemini
    • 【模型接入】Stable Diffusion
    • 【模型接入】Midjourney
    • 【模型接入】Suno
    • 【模型接入】Grok
    • 【模型接入】阶跃星辰
    • 移动端 AI 大模型
  • IoT物联网手册

    • 功能开启
    • 产品管理
    • 设备管理
    • 物模型配置
    • 设备网关与子设备
    • 设备动态注册
    • 设备影子
    • 消息透传与数据解析
    • 设备接入(概述)
    • 设备接入(HTTP 协议)
    • 设备接入(MQTT 协议)
    • 设备接入(EMQX 协议)
    • 设备接入(TCP 协议)
    • 设备接入(UDP 协议)
    • 设备接入(WebSocket 协议)
    • 设备接入(CoAP 协议)
    • 设备接入(Modbus Client 模式)
    • 设备接入(Modbus Server 模式)
    • 设备接入(自定义协议)
    • 场景联动
    • 数据流转
    • 告警配置
    • OTA 固件升级
    • 移动端 IoT 物联网
    • 设备网关合并部署
  • MES手册

    • MES 演示
    • 功能开启
    • 【基础】物料产品、分类、计量单位
    • 【基础】客户管理、供应商管理
    • 【基础】车间设置、工作站设置
    • 【基础】编码规则
    • 【生产】工序设置、工艺流程
    • 【生产】生产工单
    • 【生产】生产排产、工序流转卡
    • 【生产】生产报工
    • 【生产】安灯配置、安灯呼叫
    • 【生产】工作记录
    • 【仓库】仓库与库区库位、条码赋码、SN码
    • 【仓库】批次管理、库存现有量、库存事务
    • 【仓库】到货通知、采购入库、采购退货
    • 【仓库】生产领料、生产退料、物料消耗
    • 【仓库】产品产出、产品入库
    • 【仓库】发货通知、销售出库、销售退货
    • 【仓库】外协发料、外协入库
    • 【仓库】其他入库、其他出库
    • 【仓库】调拨单、装箱管理
    • 【仓库】库存盘点
    • 【质量】检测项设置、常见缺陷
    • 【质量】质检方案
    • 【质量】来料检验(IQC)
    • 【质量】过程检验(IPQC)
    • 【质量】出货检验(OQC)
    • 【质量】退货检验(RQC)
    • 【质量】待检任务、检验结果、缺陷记录
    • 【设备】设备类型、设备台账
    • 【设备】点检保养项目、点检保养方案
    • 【设备】点检记录、保养记录、维修单
    • 【工具】工具类型、工装夹具台账
    • 【排班】班组设置、节假日设置
    • 【排班】排班计划、排班日历
    • 移动端 MES
  • WMS手册

    • WMS 演示
    • 功能开启
    • 【基础】仓库
    • 【基础】商品、SKU、分类、品牌
    • 【基础】往来企业(供应商、客户)
    • 【库存】库存记录、流水、统计
    • 【单据】入库
    • 【单据】出库
    • 【单据】移库
    • 【单据】盘库
    • 【其它】WMS、MES、ERP 对比
    • 移动端 WMS
  • HRM人力资源

    • HRM 演示
    • 功能开启
    • 【组织】工作台、组织架构
    • 【员工】员工管理
    • 【招聘】招聘管理
    • 【考勤】考勤管理
    • 【社保】社保管理
    • 【薪资】计薪设置、薪资档案
    • 【薪资】月度工资、工资条
    • 【绩效】绩效模板、绩效计划
    • 【绩效】绩效考核、绩效档案
    • 移动端 HRM
  • FMS财务管理

    • FMS 演示
    • 功能开启
    • 【设置】账套管理、财务参数、财务指标
    • 【设置】币别、科目、辅助核算、初始余额
    • 【设置】凭证字、常用摘要、凭证模板
    • 【凭证】凭证管理
    • 【账簿】账簿管理
    • 【报表】财务报表
    • 【结账】期末结账
    • 移动端 FMS
  • PMS项目管理

    • PMS 演示
    • 功能开启
    • 【项目中心】工作台与项目管理
    • 【项目中心】项目详情与迭代
    • 【项目中心】工作项与协作
    • 【知识中心】知识库管理
    • 【知识中心】文档与协作
    • 移动端 PMS
  • OA协同办公

    • OA 演示
    • 功能开启
    • 【协作】日程、任务、计划与汇报
    • 【协作】公告、讨论、通讯录与笔记
    • 【办公】企业邮箱
    • 【办公】企业云盘
    • 【行政】办公用品、用印管理
    • 【行政】会议室、车辆管理
    • 【流程】公文管理
    • 【流程】出差、费用报销
    • 【流程】考勤、请假、加班、转正与离职
    • 移动端 OA
  • IM即时通讯手册

    • IM 演示
    • 功能开启
    • 【好友】好友关系、好友申请
    • 【群聊】群组、群成员、入群申请
    • 【消息】私聊、群聊、频道消息
    • 【频道】频道、频道素材
    • 【内容】表情、敏感词
    • 【通话】语音通话、视频通话、共享屏幕
    • 【WebSocket】实时推送与离线消息
    • 移动端 IM 即时通讯
  • 公众号手册

    • 功能开启
    • 公众号接入
    • 公众号粉丝
    • 公众号标签
    • 公众号消息
    • 模版消息
    • 自动回复
    • 公众号菜单
    • 公众号素材
    • 公众号图文
    • 公众号统计
    • 移动端公众号管理
  • 系统手册

    • 短信配置
    • 邮件配置
    • 站内信配置
    • Webhook(钉钉、飞书、企微)
    • 数据脱敏
    • 敏感词
    • 地区 & IP 库
  • 运维手册

    • 开发环境
    • Linux 部署
    • Docker 部署
    • Jenkins 部署
    • 宝塔部署
    • 1Panel 部署
    • Docker Compose 部署
    • Kubernetes 部署
    • HTTPS 证书
    • 服务监控
    • 生产环境安全
      • 1. 生产配置从哪里来?
      • 2. 全局配置
        • 2.1 示例
        • 2.2 Swagger、Knife4j 接口文档
        • 2.3 Actuator 监控端点
        • 2.4 Druid 监控
        • 2.5 Spring Boot Admin
        • 2.6 登录、验证码与密钥
      • 3. 模块配置与数据库
        • 3.1 配置文件
        • 3.2 数据库与后台配置
      • 4. 需要保留的业务入口
      • 5. 端口与网络边界
        • 5.1 请求链路
        • 5.2 为什么业务服务不能被直接访问?
        • 5.3 Nacos 与 XXL-Job
      • 6. Nginx 与 HTTPS
        • 6.1 注意点
        • 6.2 示例
        • 6.3 内网访问管理面
        • 6.4 客户端 IP
      • 7. 上线检查
        • 7.1 公网侧
        • 7.2 内网侧
        • 7.3 业务回归
    • Tomcat WAR 部署
    • 东方通服务器部署(TongWeb、TongHttpServer)
    • 宝兰德服务器部署(BES AppServer)
    • 内网穿透
  • 前端手册 Vue 3.x

    • 开发规范
    • 菜单路由
    • Icon 图标
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
    • CRUD 组件
    • 国际化
    • IDE 调试
    • 代码格式化
  • 前端手册 Vben 5.x

    • 开发规范
    • 菜单路由
    • 图标、主题、国际化
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
    • IDE 调试
    • 代码格式化
  • 前端手册 Vue 2.x

    • 开发规范
    • 菜单路由
    • Icon 图标
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
  • 前端手册 Admin Uniapp

    • 开发规范
    • 菜单路由
    • 图标、主题、国际化
    • 字典数据
    • 系统组件
    • 通用方法
    • IDE 调试
    • 代码格式化
    • 运行发布
  • 更新日志

    • 【v2026-11】
    • 【v2026-10】
    • 【v2026-09】
    • 【v2026-08】
    • 【v2026-07】
    • 【v2026-06】
    • 【v2026-05】
    • 【v2026-04】
    • 【v2026-03】
    • 【v2026-01】
    • 【v2025-12】
    • 【v2025-11】
    • 【v2025-10】
    • 【v2025-09】
    • 【v2025-08】
  • 开发指南
  • 运维手册
芋道源码
2026-11-01
目录

生产环境安全

本小节,汇总项目部署到公网生产环境前,需要检查的配置项、默认数据和网络边界。

适用范围

  • 本文只覆盖项目自带的配置、初始化数据,以及 Nginx、Gateway 与端口的收口,不能代替代码审计、漏洞扫描、主机加固和依赖升级。
  • 按本文完成配置,不代表系统已经安全,请结合自己启用的服务和部署方式检查。
  • 文中的 <...> 都是占位符,需要替换成你自己的值。不要把真实的密码、密钥提交到代码仓库或 Nacos 的公开命名空间。

# 1. 生产配置从哪里来?

每个服务都有自己的配置文件,例如 yudao-module-system/yudao-module-system-server/src/main/resources、yudao-gateway/src/main/resources:

文件 用途 生产注意
application.yaml 所有环境共用 其中的密钥是示例值,需要在生产配置中覆盖
application-local.yaml 本地开发 system-server、infra-server 开启了 yudao.security.mock-enable 模拟登录,关闭了 yudao.captcha.enable 验证码,不能用于生产
application-dev.yaml 开发、测试环境 Actuator 全部开放;system-server 的 yudao.demo 为 true(演示模式)
Nacos 中的 <服务名>-<profile>.yaml 由 spring.config.import 加载 优先级高于本地文件,可以集中管理生产配置

推荐的做法:

① 为每个服务准备 prod 配置(本地的 application-prod.yaml,或 Nacos 中的 <服务名>-prod.yaml),再合并「2.1 示例」中的安全配置。项目没有跨服务的共享配置,每个启用的服务都需要配置。

② 启动时使用 --spring.profiles.active=prod 参数,或 SPRING_PROFILES_ACTIVE=prod 环境变量。

③ 密码、密钥使用 ${环境变量名} 引用,由启动脚本、Docker 或 K8s 的 Secret 注入。

# 2. 全局配置

# 2.1 示例

下面是业务服务(system-server、infra-server 等)prod 配置中与安全相关的片段。每个顶层配置项只出现一次,避免和已有内容重复。

springdoc:
  api-docs:
    enabled: false # 关闭 /v3/api-docs 接口(OpenAPI JSON)
  swagger-ui:
    enabled: false # 关闭 /swagger-ui 页面

knife4j:
  enable: false # 关闭 Knife4j 增强

management:
  endpoints:
    web:
      exposure:
        include: health # 只通过 HTTP 暴露 health 端点
  endpoint:
    health:
      show-details: never # 不返回数据库、Redis 等组件的详情
      show-components: never

spring:
  cloud:
    nacos:
      username: ${NACOS_USERNAME} # Nacos 开启鉴权后需要,见「5.3」
      password: ${NACOS_PASSWORD}
  datasource:
    druid:
      web-stat-filter:
        enabled: false # 关闭 Web 统计
      stat-view-servlet:
        enabled: false # 关闭 /druid 控制台

mybatis-plus:
  encryptor:
    password: ${YUDAO_ENCRYPTOR_PASSWORD} # 见「2.6」:各服务保持一致,已有加密数据时不要随意更换

yudao:
  captcha:
    enable: true # 开启图片验证码(system-server)
  security:
    mock-enable: false # 关闭模拟登录
  demo: false # 关闭演示模式(system-server 的 dev 配置为 true)

system-server 还需要配置短信验证码的范围:

yudao:
  sms-code:
    begin-code: 100000 # 短信验证码在 [begin-code, end-code] 之间随机
    end-code: 999999

gateway-server 网关需要关闭 Knife4j 的聚合文档,并收紧 Actuator:

knife4j:
  gateway:
    enabled: false # 关闭 Knife4j 聚合文档

management:
  endpoints:
    web:
      exposure:
        include: health

# 2.2 Swagger、Knife4j 接口文档

配置项 位置 作用
springdoc.api-docs.enabled 每个业务服务 关闭 /v3/api-docs 接口,即该服务全部接口的定义
springdoc.swagger-ui.enabled 每个业务服务 只关闭 /swagger-ui 页面
knife4j.enable 每个业务服务 关闭 Knife4j 的增强功能
knife4j.gateway.enabled gateway-server 只关闭聚合页面

注意,Gateway 为每个服务配置了 RewritePath=/admin-api/<模块>/v3/api-docs, /v3/api-docs 规则,例如 /admin-api/system/v3/api-docs 会被转发到 system-server 的 /v3/api-docs。并且各服务的 SecurityConfiguration 对 /v3/api-docs/** 设置了免登录。

所以,只关闭网关的聚合页面,不能阻止通过网关读取接口定义。需要在每个服务关闭 springdoc.api-docs.enabled,并在 Nginx 拦截这类路径,见「6.2」。

# 2.3 Actuator 监控端点

各服务、网关的 application-local.yaml、application-dev.yaml 中,management.endpoints.web.exposure.include 都是 '*',即开放所有端点。并且各业务服务对 /actuator/** 设置了免登录。

Actuator 是否生效,以启动日志中 Exposing ... beneath base path '/actuator' 这一行为准,也可以在服务所在的服务器上请求 /actuator 确认。

生产环境下,按「2.1 示例」只暴露 health。如果需要保留更多观测端点,必须保证服务端口只有内网可以访问,见「5. 端口与网络边界」。需要账号密码时,见「6.3」的 Nginx Basic 认证。

为什么不能直接配置 `spring.security.user` 账号密码?

业务服务使用的 YudaoWebSecurityConfigurerAdapter 自定义了基于访问令牌的 SecurityFilterChain,没有开启 HTTP Basic;各服务的 SecurityConfiguration 又对 /actuator、/actuator/** 设置了 permitAll()。所以只配置 spring.security.user.name、spring.security.user.password,不会保护 Actuator 端点。

如果希望由应用自己校验账号密码,需要为 /actuator/** 单独编写一个 SecurityFilterChain,并去掉上述 permitAll(),项目没有内置这个开关。不改代码时,可以使用「6.3」的网段限制 + Nginx Basic 认证。

Spring Boot Admin、Druid 有各自的账号密码,按「2.4」「2.5」配置即可。

management.endpoint.<id>.enabled 在 Spring Boot 3.4 起废弃,改用 management.endpoint.<id>.access。shutdown 端点默认就是关闭的,没有加入 exposure.include 时也不会通过 HTTP 暴露。

# 2.4 Druid 监控

各服务的 application-dev.yaml 中,spring.datasource.druid.stat-view-servlet.enabled 为 true,allow、login-username、login-password 都为空,并且各服务对 /druid/** 设置了免登录。

  • 不需要时:按「2.1 示例」关闭 stat-view-servlet 和 web-stat-filter。filter.stat 的慢 SQL 日志不受影响。
  • 需要时:设置 login-username、login-password,并且只通过内网访问对应服务的端口。

# 2.5 Spring Boot Admin

  • Server 端:内嵌在 infra-server 中,默认没有启用。需要同时取消 yudao-module-infra-server 的 pom.xml 中 spring-boot-admin-starter-server 依赖的注释,以及 AdminServerConfiguration 类上 @EnableAdminServer 注解的注释。不需要时,保持现状即可。
  • 登录认证:启用后,AdminServerConfiguration 为 spring.boot.admin.context-path(默认 /admin)下的路径注册了独立的认证:浏览器使用表单登录,Client 注册使用 HTTP Basic。账号、密码读取 spring.boot.admin.client.username、spring.boot.admin.client.password,未配置时都是 admin。
  • Client 端:spring.boot.admin.client.enabled: false 只是停止向 Server 注册,不会关闭 Server 和 /admin 页面。

需要使用时:

① 修改上述账号、密码,通过环境变量注入。

② /admin 只允许内网或 VPN 访问。注意,Gateway 有一条 Path=/admin/** 的路由转发到 infra-server,所以公网 Nginx 不能把 /admin 转发给网关。

③ 修改 spring.boot.admin.frame-ancestors 为管理后台的域名。

④ 不要删除 spring.boot.admin.context-path 配置,AdminServerConfiguration 依赖它确定认证拦截的路径范围。

更多说明,可见 《服务监控》 文档。

# 2.6 登录、验证码与密钥

配置项 位置 生产要求
yudao.security.mock-enable 各服务 必须为 false。开启后,以 yudao.security.mock-secret 开头的 token 可以模拟任意用户
yudao.captcha.enable system-server 开启。前端的 VITE_APP_CAPTCHA_ENABLE 需要保持一致
yudao.sms-code.begin-code、end-code system-server 的 application.yaml 默认两者相同,即固定验证码,改为一个范围
mybatis-plus.encryptor.password 各服务的 application.yaml 上线前替换,并在各服务保持一致。已有加密数据(例如 infra_data_source_config.password)后再更换,旧数据将无法解密
yudao.api-encrypt.* system-server 等 默认关闭,启用时替换 request-key、response-key
yudao.demo system-server 演示模式会拦截写操作。dev 配置为 true,生产按需设置
xxl.job.accessToken 各服务的 application.yaml 替换示例值,并与 XXL-Job 调度中心的 accessToken 一致,见「5.3」

免登录的接口,有三个来源:接口上的 @PermitAll 注解、yudao.security.permit-all_urls 配置项、各服务 SecurityConfiguration 中的 permitAll()。新增免登录接口时,需要接口自身完成签名或令牌校验。

# 3. 模块配置与数据库

只需要检查已启用的服务。

# 3.1 配置文件

服务 配置项 处理要求
通用 spring.datasource.dynamic.datasource.*.username、password,spring.data.redis.password,MQ 的账号密码 使用独立账号和强密码,通过环境变量注入。Redis 生产需要开启密码
system / member justauth.type.*.client-id、client-secret,wx.mp.app-id、secret,wx.miniapp.appid、secret 换成自己的应用,不用的三方登录直接删除
pay yudao.pay.order-notify-url、refund-notify-url、transfer-notify-url 改为生产域名下的 HTTPS 地址,不要保留内网穿透地址
trade yudao.trade.express.* 中快递鸟、快递 100 的 key 换成自己的密钥
ai spring.ai.*.api-key、yudao.ai.*.api-key,yudao.ai.midjourney.notify-url 只开启用到的平台,通过环境变量注入;回调改为生产域名
ai spring.ai.mcp.server.enabled(默认 false) 开启后,MCP 端点免登录,见「4」
bpm flowable.database-schema-update 可选:表结构稳定后改为 false
iot yudao.iot.gateway.token.secret IoT 网关 application.yaml 中是示例值,替换为至少 32 位的随机值
iot yudao.iot.gateway.protocols 中各协议的 enabled、port,emqx 协议的 mqtt-username、mqtt-password,SSL 的 key-store-password、trust-store-password 只开启用到的协议,替换示例账号密码
iot yudao.iot.gateway.rpc.url 指向 iot-server 的内网地址

# 3.2 数据库与后台配置

以下数据来自初始化 SQL,建议在管理后台对应的页面修改。不要直接删除数据行,部分数据是系统运行所必需的。

其中 infra_config 是参数配置表,下表中它的几行是配置项的 config_key 值:按 config_key 找到对应的配置项,再修改它的 value。

表 字段 / 配置 key 处理要求
system_users username、password 登录后修改内置账号(例如 admin)的密码,不用的演示账号停用
infra_config system.user.init-password 新建用户的初始密码,默认是弱口令,改为强密码
infra_config system.user.register-enabled 不需要后台自助注册时,改为 false
infra_config url.druid、url.spring-boot-admin、url.swagger、url.skywalking 前端监控菜单 iframe 的地址,填内网地址或留空
system_oauth2_client client_id、secret、redirect_uris、authorized_grant_types、status client_id 为 default 的客户端是后台登录使用的,不要删除、禁用或改名。其它演示客户端不用时禁用,使用时更换 secret、收紧 redirect_uris
system_social_client client_id、client_secret、agent_id、public_key 换成自己的应用
system_sms_channel api_key、api_secret、callback_url 换成自己的短信账号
system_mail_account username、password、host、port、ssl_enable 换成自己的邮箱,开启 SSL
infra_file_config config(JSON,包含存储的访问密钥) 换成自己的存储配置
infra_data_source_config url、username、password password 由 mybatis-plus.encryptor.password 加密
pay_app order_notify_url、refund_notify_url、transfer_notify_url 改为生产域名
pay_channel config(JSON,包含商户号、密钥、证书) 换成自己的商户配置
mp_account app_id、app_secret、token、aes_key 换成自己的公众号
ai_api_key api_key、url 换成自己的密钥

# 4. 需要保留的业务入口

以下接口是业务必需的,不能一刀切封禁。它们大多在 /admin-api/ 下,经 Nginx、Gateway 转发即可。

路径 用途 鉴权方式 Nginx
/admin-api/pay/notify/order/{channelId}、refund/{channelId}、transfer/{channelId} 支付渠道回调 免登录,由支付渠道的签名校验 随 /admin-api/ 转发
/admin-api/mp/open/{appId} 公众号消息、服务器地址校验 免登录,校验微信签名 随 /admin-api/ 转发
/admin-api/ai/image/midjourney/notify Midjourney 回调 免登录 启用 AI 时保留
/admin-api/infra/file/{configId}/get/** 文件读取 免登录 保留。只有读取免登录,上传、删除等接口仍需登录和权限
/infra/ws WebSocket,网关转发到 infra-server 通过 ?token= 参数传递访问令牌 需要单独配置 Upgrade 头
/jmreport/**、/drag/**、/jimubi/** 积木报表、仪表盘,网关转发到 report-server Spring Security 放行,积木内部由 JmReportTokenServiceImpl 校验访问令牌 启用 report 服务时才转发,并参考积木官方的 《生产安全》 (opens new window) 文档
/sse、/mcp/message MCP Server,网关转发到 ai-server 免登录 未启用时不转发;启用时只对受信的客户端开放
IoT 网关的协议端口 设备接入 由各协议的设备认证完成 不经过 Nginx 和 Gateway,按启用的协议开放端口

WebSocket 的访问令牌在 URL 参数中,会出现在 Nginx 的 access log 里,注意控制日志文件的访问权限。

# 5. 端口与网络边界

# 5.1 请求链路

浏览器 / App ──443──> Nginx ──内网──> gateway-server(48080)──内网──> 各业务服务(48081、48082 ...)
设备 ──────────────按启用的协议端口──> IoT 网关 ──内网 /rpc-api/iot/**──> iot-server
端口 服务 公网
80、443 Nginx 开放
48080 gateway-server 不开放,只允许 Nginx 访问
48081 及以上 各业务服务 不开放,只允许网关和服务之间访问
8848、9848 等 Nacos 不开放
XXL-Job 调度中心、Spring Boot Admin、SkyWalking 等 基础服务 不开放,通过内网或 VPN 访问
3306、6379、MQ 等 中间件 不开放
IoT 协议端口(例如 HTTP 8092、MQTT 1883) IoT 网关 按启用的协议开放

友情提示:Docker 的端口映射

使用 docker run -p 48081:48081 时,Docker 会直接修改 iptables,可能绕过 ufw、firewalld 等主机防火墙规则。建议不映射业务服务的端口,或写成 -p 127.0.0.1:48081:48081,并在云厂商的安全组中限制。

# 5.2 为什么业务服务不能被直接访问?

关闭 Swagger、Actuator 只能减少暴露的接口,不能代替网络隔离。原因是服务之间存在“信任内网”的设计:

① 内部身份头:网关校验访问令牌后,把登录用户放到 login-user 请求头中转发给服务。服务的 TokenAuthenticationFilter 会优先信任这个请求头,不再校验令牌。网关会先清除客户端传入的 login-user、data-permission-enable 请求头,但直接访问服务端口时,没有这一步。

② RPC 接口:各服务的 SecurityConfiguration 对 /rpc-api/** 设置了免登录,供 Feign 在服务之间调用。

③ 网关不拦截未登录请求:网关的 TokenAuthenticationFilter 在没有令牌时,仍然继续转发,是否需要登录由服务自己判断。所以网关自身也不能直接暴露,而且 Nginx 只转发需要的路径。

因此,部署时需要保证:业务服务、网关的端口,只能从内网访问。

# 5.3 Nacos 与 XXL-Job

  • Nacos:开启 nacos.core.auth.enabled,并替换 nacos.core.auth.plugin.nacos.token.secret.key、nacos.core.auth.server.identity.key、nacos.core.auth.server.identity.value,设置方式参见 《Docker 部署》 的「1.5 安装 Nacos」。然后在各服务配置 spring.cloud.nacos.username、password。服务要先用这组账号密码连接 Nacos,才能拉取远程配置,所以它们必须写在本地配置文件,或通过环境变量提供,不能只写在 Nacos 的远程配置里。Nacos 中保存了各服务的配置,包括数据库密码,控制台不能对公网开放。
  • XXL-Job:xxl.job.accessToken 用于调度中心和执行器之间的通信校验,替换示例值,两边保持一致。执行器端口(xxl.job.executor.port)和调度中心都只在内网访问,并修改调度中心自己的登录账号密码。

# 6. Nginx 与 HTTPS

# 6.1 注意点

  • Nginx 匹配 location 的优先级是:= 精确匹配,然后是带 ^~ 的最长前缀,然后按书写顺序匹配正则,最后才是普通前缀。拦截规则使用正则时,必须写在 /admin-api/ 等转发规则之前。
  • 被拦截的路径,如果没有命中任何转发规则,会落到前端的 try_files ... /index.html 兜底,返回 200 和前端页面。显式返回 404,才能在「7. 上线检查」时明确区分。
  • 不要使用 location / 直接转发到网关,否则网关的 /admin/**、/jmreport/**、/sse 等路由,以及网关自己的 /actuator 都会暴露。

# 6.2 示例

在 《Docker Compose 部署》 的 nginx/default.conf 基础上,增加 HTTPS 和拦截规则:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name <你的域名>;
    return 301 https://$host$request_uri; # HTTP 跳转 HTTPS
}

server {
    listen 443 ssl;
    server_name <你的域名>;

    ssl_certificate     /etc/nginx/cert/<证书文件>.pem; # 证书申请,见《HTTPS 证书》
    ssl_certificate_key /etc/nginx/cert/<证书文件>.key;

    root /usr/share/nginx/html; # 前端 dist 目录
    index index.html;
    client_max_body_size 32m; # 与后端 spring.servlet.multipart.max-request-size 保持一致

    # ① 拦截:网关为每个服务重写的接口文档路径,例如 /admin-api/system/v3/api-docs
    location ~ ^/(admin-api|app-api)/[^/]+/v3/api-docs {
        return 404;
    }

    # ② 拦截:管理端点
    location = /doc.html { return 404; }
    location ~ ^/(actuator|druid|admin|swagger-ui|v3/api-docs|webjars|rpc-api)(/|$) {
        return 404;
    }

    # ③ 管理后台 API、用户 App API。支付、公众号回调和文件读取都在其中,不要单独拦截
    location ~ ^/(admin-api|app-api)/ {
        proxy_pass http://<网关内网地址>:48080;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr; # 最外层 Nginx 使用 $remote_addr 覆盖,见「6.4」
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header login-user ""; # 不转发客户端传入的内部身份头(网关也会清除)
        proxy_set_header Connection "";
        proxy_buffering off; # 流式响应(SSE)不缓冲
        proxy_read_timeout 300s;
    }

    # ④ WebSocket,网关转发到 infra-server
    location ^~ /infra/ws {
        proxy_pass http://<网关内网地址>:48080;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header login-user "";
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 3600s;
    }

    # ⑤ 按需:启用积木报表时,才取消注释
    # location ~ ^/(jmreport|drag|jimubi)/ {
    #     proxy_pass http://<网关内网地址>:48080;
    #     proxy_set_header Host $http_host;
    #     proxy_set_header X-Real-IP $remote_addr;
    #     proxy_set_header X-Forwarded-For $remote_addr;
    #     proxy_set_header login-user "";
    # }

    # ⑥ 前端 history 路由的兜底
    location / {
        try_files $uri $uri/ /index.html;
    }
}

# 6.3 内网访问管理面

如果需要使用 Spring Boot Admin、Swagger 等管理页面,可以增加一个只监听内网地址的 server,安全组不对公网开放该端口:

server {
    listen <内网 IP>:8081; # 只监听内网地址

    allow <VPN 或办公网段>; # 例如 10.8.0.0/24
    deny  all;

    # 网关自己的 Actuator:在网段限制之外,再加一层 Nginx Basic 认证
    location ^~ /actuator {
        auth_basic           "actuator";
        auth_basic_user_file /etc/nginx/.htpasswd-actuator; # 不要提交到代码仓库
        proxy_pass http://<网关内网地址>:48080;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Authorization ""; # 不把 Basic 认证头传给后端
    }

    # 业务服务的 Actuator:网关不会转发,需要直接指向服务的内网端口
    # 例如 /system-actuator/health -> system-server 的 /actuator/health,其它服务按需复制
    location ^~ /system-actuator/ {
        auth_basic           "actuator";
        auth_basic_user_file /etc/nginx/.htpasswd-actuator;
        proxy_pass http://<system-server 内网地址>:48081/actuator/;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Authorization "";
    }

    # Spring Boot Admin、Swagger 等页面,经网关转发,使用各自的账号密码登录
    location / {
        proxy_pass http://<网关内网地址>:48080;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
}

htpasswd 文件在服务器上创建,执行后按提示输入密码,密码不会留在命令历史里:

# htpasswd 命令来自 httpd-tools(CentOS)或 apache2-utils(Ubuntu)
htpasswd -c /etc/nginx/.htpasswd-actuator <用户名> # -c 表示新建文件,只在首次创建时使用
chown root:<Nginx 进程用户组> /etc/nginx/.htpasswd-actuator # 常见为 nginx 或 www-data
chmod 640 /etc/nginx/.htpasswd-actuator # 只允许 root 和 Nginx 进程用户组读取

<Nginx 进程用户组> 按 Nginx worker 进程实际的运行组填写,可以查看 nginx.conf 中的 user 指令。如果该组读不到文件,即使密码正确,Nginx 也会返回 500。以后新增账号时,去掉 -c 参数,例如 htpasswd /etc/nginx/.htpasswd-actuator <新用户名>,否则会覆盖已有的账号。

几个注意点:

  • 网段限制仍然是主要的保护手段。allow、deny 和 auth_basic 同时存在时,默认两者都要满足,Basic 认证只是多加一层,不能因此把网关、业务服务或这个端口开放到公网。
  • 网关的 /actuator 只是网关自己的端点。网关的业务路由只转发 /admin-api/<模块>/** 等路径,业务服务的 /actuator 不会经网关转发,所以示例单独指向 system-server 的内网端口。
  • Basic 认证的账号密码只做了 Base64 编码,必须通过 VPN 访问,或者为这个 server 配置 HTTPS。
  • 通过该入口拉取指标的监控客户端,例如 Prometheus,需要配置同样的账号密码(Prometheus 的 basic_auth)。
  • 不要在 /admin 上叠加 Nginx Basic 认证:Spring Boot Admin Client 注册时,也使用 HTTP Basic 的 Authorization 请求头,两者会冲突。
  • Spring Boot Admin、Druid 仍然需要配置各自的账号密码。Druid 控制台不经过网关,需要直接访问对应服务的内网端口。

# 6.4 客户端 IP

后端通过 X-Forwarded-For、X-Real-IP 等请求头获取客户端 IP,用于登录日志、操作日志等。最外层 Nginx 如果使用 $proxy_add_x_forwarded_for,会保留客户端自己传入的值,导致 IP 可以伪造。所以:

  • Nginx 是最外层时,使用 proxy_set_header X-Forwarded-For $remote_addr; 覆盖。
  • Nginx 前面还有 SLB、CDN 时,使用 set_real_ip_from <SLB 网段>; 和 real_ip_header X-Forwarded-For;,让 $remote_addr 变成真实的客户端 IP。allow、deny 也依赖它。

# 7. 上线检查

# 7.1 公网侧

在公网的机器上执行:

DOMAIN=https://<你的域名>
for p in /actuator /actuator/env /druid/index.html /admin /admin/applications \
         /v3/api-docs /doc.html /admin-api/system/v3/api-docs /admin-api/infra/v3/api-docs \
         /rpc-api/system/user/get; do
  printf '%-34s %s\n' "$p" "$(curl -s -o /dev/null -w '%{http_code}' "$DOMAIN$p")"
done

预期都是 404。如果返回 200,并且内容是前端的 index.html,说明请求落到了 SPA 的兜底,没有命中拦截规则,需要检查 location 的写法。

再执行 curl -s $DOMAIN/admin-api/system/user/profile/get(不携带访问令牌)。该接口需要登录,预期返回 code 为 401 的 JSON,例如 {"code":401,"data":null,"msg":"账号未登录"},说明 Nginx 和网关的转发都正常。如果返回前端的 HTML 页面,或网关未匹配到路由的错误(例如 404),都不算通过。

最后,从公网检查网关、业务服务、Nacos 的端口,例如 nc -zv -w 3 <公网 IP> 48081、nc -zv -w 3 <公网 IP> 8848,预期连接失败。

# 7.2 内网侧

在服务所在的机器上执行:

curl -s http://127.0.0.1:48081/actuator          # 只应包含 health;未引入 Actuator 时,返回未找到
curl -s http://127.0.0.1:48081/v3/api-docs | grep -c '"openapi"'   # 预期为 0
curl -s http://127.0.0.1:48080/actuator          # 网关同样只应包含 health

服务对不存在的路径,可能返回 HTTP 200,但 JSON 中的 code 为 404。请以响应内容判断,不要只看状态码。

如果启用了 Spring Boot Admin,从 VPN 访问 /admin,确认需要输入账号密码。登录 Nacos 控制台,确认需要账号密码。

# 7.3 业务回归

  • 管理后台、用户 App 可以正常登录,登录需要图片验证码。
  • 短信验证码是随机值,原来的固定验证码无法通过。
  • 支付渠道的沙箱回调可以到达,订单状态正常变化。
  • 公众号的服务器地址校验可以通过。
  • WebSocket 可以连接,文件链接可以打开。
  • XXL-Job 的定时任务可以正常调度。
  • 启用积木报表时,登录后可以预览报表;未登录时无法访问报表数据。
  • 启用 IoT 时,设备可以通过开放的协议端口接入。
服务监控
Tomcat WAR 部署

← 服务监控 Tomcat WAR 部署→

Theme by Vdoing | Copyright © 2019-2026 芋道源码 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×