博文

六层级用户权限管理:一段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 → 写入 10gModbusTCP.iUserCMD
  • PLC 执行比对 → 成功后 iUserLevel 变更 → HMI 检测到变更后刷新界面
  • 退出时写入 20iUserCMD → 权限降级到 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 平台。

← 返回博文列表