六层级用户权限管理:一段ST代码读懂设备操作安全体系
笔记
工业设备不同于消费电子——谁在什么时间能做什么操作,必须严格受控。今天拆解一段ST代码,看如何用 6个用户等级 + 密码比对 实现设备权限管理体系。
一、功能概述
这段程序实现了一个 6层级用户权限管理系统,通过 Modbus TCP 接口实现远程登录/退出:
| 等级 | 角色名称 | 权限范围 |
|---|---|---|
| 0 | 👤 Visitor(访客) | 仅查看,不可操作 |
| 1 | 🔘 Switch(开关功能) | 基础启停操作 |
| 2 | ⚙️ Operator(参数变更) | 修改运行参数 |
| 3 | 🔧 Service(设备维护) | 维护模式操作 |
| 4 | 🛡️ Admin(管理员) | 全部权限 |
| 5 | 👑 SuperAdmin(超级管理员) | 最高权限,可管理系统配置 |
二、完整代码(逐行注释版)
(*
Log:
2024-12-23
1. 初版验证完成
1.1 用户等级
1.1.1 访客 — 仅查看
1.1.2 开关功能 — 基础启停
1.1.3 参数变更 — 修改参数
1.1.4 设备维护 — 维护操作
1.1.5 管理员 — 全部权限
1.1.6 超级管理员 — 最高权限
1.2 比对用户密码进行权限的切换
1.3 通过可见度去切换用户的保存密码输入框
*)
// ==========================================================**
// 第一部分:用户命令解析(登录/退出)
// 通过 Modbus TCP 下发的命令码执行
// **==========================================================
CASE gModbusTCP.iUserCMD OF
// —— 命令 10:登录 ——
10:
// 遍历用户密码列表(6个等级,对应6组密码)
FOR iUserList := 0 TO 5 BY 1 DO
// 将输入的密码与预存密码逐一比对
IF gModbusTCP.StrPassWord = gPV.EasyUserPassList[iUserList] THEN
// 密码匹配成功 → 设定用户等级为当前索引
// 例如:匹配到索引2的密码 → iUserLevel = 2(Operator)
gModbusTCP.iUserLevel := iUserList;
EXIT; // 找到匹配后立即跳出循环
END_IF;
END_FOR;
// 无论登录成功与否,清理密码和命令
gModbusTCP.StrPassWord := ' '; // 清空密码(安全:不在内存中保留明文密码)
gModbusTCP.iUserCMD := 0; // 命令复位
// —— 命令 20:退出 ——
20:
gModbusTCP.iUserLevel := 0; // 降级为访客权限
gModbusTCP.StrPassWord := ' '; // 清空密码
gModbusTCP.iUserCMD := 0; // 命令复位
END_CASE;
// ==========================================================**
// 第二部分:根据用户等级分配显示名称
// 每个等级对应一个操作角色,用于 HMI/上位机展示
// **==========================================================
CASE gModbusTCP.iUserLevel OF
1:
gModbusTCP.StrUserName := 'Switch'; // 开关功能操作员
2:
gModbusTCP.StrUserName := 'Operator'; // 参数变更操作员
3:
gModbusTCP.StrUserName := 'Service'; // 设备维护工程师
4:
gModbusTCP.StrUserName := 'Admin'; // 管理员
5:
gModbusTCP.StrUserName := 'SuperAdmin'; // 超级管理员
ELSE
gModbusTCP.StrUserName := 'Visitor'; // 默认:访客(含等级0)
END_CASE;
三、登录验证流程图解
HMI输入密码
│
▼
┌─────────────┐
│ iUserCMD=10 │
│ (登录命令) │
└──────┬──────┘
▼
┌─────────────────────┐
│ FOR 循环 i=0 TO 5 │
│ 逐个比对6组密码 │
└──────┬──────┘
│
├── 匹配成功 ──→ iUserLevel = i
│ (赋予对应等级权限)
│
└── 全部不匹配 ─→ iUserLevel 不变
(保持当前等级或访客)
│
▼
┌─────────────────────┐
│ 清空密码 & 复位命令 │
│ (安全处理) │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ CASE iUserLevel │
│ 分配显示名称 │
└─────────────────────┘
四、数据结构说明
// —— 命令接口(通过 Modbus TCP 下发给 PLC)——
gModbusTCP.iUserCMD : INT; // 命令码:10=登录,20=退出
gModbusTCP.StrPassWord : STRING; // 用户输入的密码
// —— 权限状态(PLC 内部维护)——
gModbusTCP.iUserLevel : INT; // 当前用户等级:0~5
gModbusTCP.StrUserName : STRING; // 当前用户显示名称
// —— 密码配置(PV = 持久化变量,掉电保存)——
gPV.EasyUserPassList[6] : STRING; // 6个等级的预设密码
// 索引0 → 访客(通常为空或禁用)
// 索引1 → Switch 密码
// 索引2 → Operator 密码
// 索引3 → Service 密码
// 索引4 → Admin 密码
// 索引5 → SuperAdmin 密码
五、权限控制扩展思路
在实际项目中,可以在代码的其他位置通过判断 iUserLevel 来决定是否允许某操作:
// 示例:仅 Operator(2级)及以上才能修改参数
IF gModbusTCP.iUserLevel >= 2 THEN
// 允许更改参数
gPV.TargetSpeed := 100;
ELSE
// 无权限,拒绝操作
gHMI.AlarmMsg := '权限不足,请登录高级账号';
END_IF;
// 示例:仅 Admin(4级)及以上才能进入系统配置
IF gModbusTCP.iUserLevel >= 4 THEN
// 显示系统配置页面
END_IF;
六、设计中值得注意的安全细节
| 安全措施 | 说明 |
|---|---|
| 登录后清空密码 | gModbusTCP.StrPassWord := ' ',避免密码在内存中常驻 |
| 退出后降级为访客 | 防止他人复用当前登录态 |
| 密码列表预存 | 密码在 gPV 持久化变量中预置,不在代码中硬编码 |
| 循环比对+EXIT | 匹配到即退出,避免无意义的继续遍历 |
| ELSE 缺省处理 | 未匹配到等级时默认为 Visitor,永远不会出现无权限状态 |
七、应用场景举例
场景1:HMI 登录界面
┌───────────────────────────┐
│ 🔒 用户登录 │
│ │
│ 请输入密码:[ ]│
│ │
│ [ 登录 ] [ 退出 ] │
│ │
│ 当前用户:Visitor │
└───────────────────────────┘
- 操作员输入密码 → Modbus TCP 写入
gModbusTCP.StrPassWord→ 写入10到gModbusTCP.iUserCMD - PLC 执行比对 → 成功后
iUserLevel变更 → HMI 检测到变更后刷新界面 - 退出时写入
20到iUserCMD→ 权限降级到 Visitor
场景2:页面可见度控制
通过 iUserLevel 控制 HMI 页面元素的可见度:
| iUserLevel | 可操作的功能 |
|---|---|
| 0(访客) | 仅查看主画面,其余页面不可见 |
| 1(开关) | 主画面 + 启停按钮 |
| 2(参数) | 主画面 + 启停 + 参数设置 |
| 3(维护) | 全部功能 + 手动维护模式 |
| 4(管理员) | 全部功能 + 用户管理 + 系统配置 |
| 5(超级管理员) | 全部权限,含密码修改 |
八、扩展建议
| 优化方向 | 实现思路 |
|---|---|
| 登录失败锁定 | 连续失败3次后锁定该账号 N 分钟 |
| 密码加密存储 | 存储密码的哈希值而非明文 |
| 操作日志记录 | 每次权限变更时记录:谁 + 什么时间 + 做了什么 |
| 超时自动退出 | 一段时间无操作后自动降级为访客 |
| 多语言用户名 | 根据 HMI 语言设置显示中文/英文角色名 |
九、总结
这段代码的核心设计思想可以用一句话概括:
用一组有序密码列表 + 一次循环比对,把用户的密码映射为等级索引,然后通过 CASE 语句把索引翻译为可读的角色名称。
gPV.EasyUserPassList[i]→ 密码输入匹配gModbusTCP.iUserLevel := iUserList→ 级别赋值Case iUserLevel→ 角色名映射
后续在整个程序中,通过比较 iUserLevel 的值就能精确控制每段代码、每个 HMI 控件是否执行或可见,简单而高效。
本文代码基于 IEC 61131-3 结构化文本(ST)语言编写,适用于 CODESYS、倍福 TwinCAT、贝加莱 Automation Studio 等主流 PLC 平台。