SAP-ABAP:SAP 权限控制深度解析:自定义程序与标准事务码的边界与协同

SAP 权限控制深度解析:自定义程序与标准事务码的边界与协同

关键词 :ABAP 权限 / AUTHORITY-CHECK / PFCG / Q_INSPTYPE / S_TCODE / SU24 / SU53

适用版本:SAP NetWeaver 7.x / S/4HANA 通用


一、问题的缘起

在 QM 检验批自建程序的开发中,一个典型场景经常引发讨论:为自定义 Z 程序添加 AUTHORITY-CHECK 控制"能看哪些工厂、哪些检验类型"之后,很多开发者会产生一个疑问------这道校验会不会影响用户在标准事务码 QA32 中看到的数据范围?

这个问题看似简单,实则牵出了 SAP 权限控制体系的完整认知框架:共同点、分水岭、代码陷阱、标准 vs 自定义的边界、以及最隐蔽的"绕过"风险。本文试图把这些问题系统化梳理清楚,给出一份可落地的权限设计参考。


二、核心结论

结论一:不会影响。

自定义 Z 程序中的 AUTHORITY-CHECK,对标准事务码(如 QA32)零影响。两套程序各自在运行时做自己的权限检查,修改 A 程序的代码永远改变不了 B 程序的行为。

结论二:但可以做到「一份配置两头生效」。

如果 Z 程序使用标准授权对象 Q_INSPTYPE(工厂+检验类型),而 QA32 工作清单原生也按 Q_INSPTYPE 过滤------那么只要 PFCG 给用户配一份 Q_INSPTYPEQA32 和 Z 程序会自动同时受控,无需写两套权限。
#mermaid-svg-rudZWFBbffEsN0Yp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rudZWFBbffEsN0Yp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rudZWFBbffEsN0Yp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rudZWFBbffEsN0Yp .error-icon{fill:#552222;}#mermaid-svg-rudZWFBbffEsN0Yp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rudZWFBbffEsN0Yp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rudZWFBbffEsN0Yp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rudZWFBbffEsN0Yp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rudZWFBbffEsN0Yp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rudZWFBbffEsN0Yp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rudZWFBbffEsN0Yp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rudZWFBbffEsN0Yp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rudZWFBbffEsN0Yp .marker.cross{stroke:#333333;}#mermaid-svg-rudZWFBbffEsN0Yp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rudZWFBbffEsN0Yp p{margin:0;}#mermaid-svg-rudZWFBbffEsN0Yp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rudZWFBbffEsN0Yp .cluster-label text{fill:#333;}#mermaid-svg-rudZWFBbffEsN0Yp .cluster-label span{color:#333;}#mermaid-svg-rudZWFBbffEsN0Yp .cluster-label span p{background-color:transparent;}#mermaid-svg-rudZWFBbffEsN0Yp .label text,#mermaid-svg-rudZWFBbffEsN0Yp span{fill:#333;color:#333;}#mermaid-svg-rudZWFBbffEsN0Yp .node rect,#mermaid-svg-rudZWFBbffEsN0Yp .node circle,#mermaid-svg-rudZWFBbffEsN0Yp .node ellipse,#mermaid-svg-rudZWFBbffEsN0Yp .node polygon,#mermaid-svg-rudZWFBbffEsN0Yp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rudZWFBbffEsN0Yp .rough-node .label text,#mermaid-svg-rudZWFBbffEsN0Yp .node .label text,#mermaid-svg-rudZWFBbffEsN0Yp .image-shape .label,#mermaid-svg-rudZWFBbffEsN0Yp .icon-shape .label{text-anchor:middle;}#mermaid-svg-rudZWFBbffEsN0Yp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rudZWFBbffEsN0Yp .rough-node .label,#mermaid-svg-rudZWFBbffEsN0Yp .node .label,#mermaid-svg-rudZWFBbffEsN0Yp .image-shape .label,#mermaid-svg-rudZWFBbffEsN0Yp .icon-shape .label{text-align:center;}#mermaid-svg-rudZWFBbffEsN0Yp .node.clickable{cursor:pointer;}#mermaid-svg-rudZWFBbffEsN0Yp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rudZWFBbffEsN0Yp .arrowheadPath{fill:#333333;}#mermaid-svg-rudZWFBbffEsN0Yp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rudZWFBbffEsN0Yp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rudZWFBbffEsN0Yp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rudZWFBbffEsN0Yp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rudZWFBbffEsN0Yp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rudZWFBbffEsN0Yp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rudZWFBbffEsN0Yp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rudZWFBbffEsN0Yp .cluster text{fill:#333;}#mermaid-svg-rudZWFBbffEsN0Yp .cluster span{color:#333;}#mermaid-svg-rudZWFBbffEsN0Yp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rudZWFBbffEsN0Yp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rudZWFBbffEsN0Yp rect.text{fill:none;stroke-width:0;}#mermaid-svg-rudZWFBbffEsN0Yp .icon-shape,#mermaid-svg-rudZWFBbffEsN0Yp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rudZWFBbffEsN0Yp .icon-shape p,#mermaid-svg-rudZWFBbffEsN0Yp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rudZWFBbffEsN0Yp .icon-shape .label rect,#mermaid-svg-rudZWFBbffEsN0Yp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rudZWFBbffEsN0Yp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rudZWFBbffEsN0Yp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rudZWFBbffEsN0Yp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} PFCG 一份授权

Q_INSPTYPE
标准事务码 QA32

原生按 Q_INSPTYPE 过滤
自定义 Z 程序

显式 AUTHORITY-CHECK
✅ 用户权限一致


三、共同点:底层是一家

无论标准程序还是自定义程序,权限控制都共用同一套 SAP 授权基础设施,本质都是 AUTHORITY-CHECK 在用户授权缓冲(SU56)里查授权对象值。

维度 说明
授权对象 都来自 SU21 定义的授权对象(标准对象如 Q_INSPTYPES_TCODE,或自建 Z* 对象)
角色分配 都靠 PFCG 把授权值填进角色、分配给用户
生命周期 都要走 生成参数文件 → 用户比较(RHAUTUPD_NEW / PFUD)→ 用户重登 三步,缺一步就"配了像没配"
判定机制 都靠 AUTHORITY-CHECK 返回 sy-subrc0=通过,4/12/24=拒绝
排查手段 失败都可用 /NSU53 抓当前缺哪个对象

从机制角度看,两者不是两套体系,而是同一套机制的两种触发方式


四、分水岭:七个维度的差异

标准程序与自定义程序真正的差异,可以从七个维度刻画:

# 区别点 标准程序 自定义程序
1 谁来写检查 SAP 已把 AUTHORITY-CHECK 写进代码,自动触发 必须自己写,不写 = 完全不检查
2 SELECT 直读 通用表工具(SE16/SM30)自动查 S_TABU_DIS SELECT 直读不触发 S_TABU_DIS
3 事务码保护 标准 T-code 自动查 S_TCODE 经 SE38/SA38 跑查 S_PROGRAM/S_DEVELOP;须用 SE93 包成 Z 事务码才走 S_TCODE
4 缺对象的处理 SAP 对 sy-subrc <> 0(含 12/24一律拒绝 新手常只判 = 4漏掉 12 → 校验形同虚设
5 可控维度 SAP 设计好了(如 QA32 只能按 工厂+检验类型 可查任意字段,灵活但责任全在开发者
6 数据级(行级)安全 BW 分析授权(RSECADMIN)标准查询自动执行 自定义直读 BW 须显式调 RSDRI 等并带授权参数
7 检查建议值(SU24) SAP 已维护,PFCG 建角色时自动带出 自定义事务码需自己SU24 维护,否则 Basis 无从下手

用一句话概括:标准程序是"出厂自带锁",自定义程序是"你爱加不加的锁"------不加就门户大开。


五、代码实践:两种典型写法

以"按工厂+检验类型控制检验批建批权限"为例(标准对象 Q_INSPTYPE)。

5.1 模式一:过滤输出(小数据量)

abap 复制代码
SELECT * FROM qals INTO TABLE @lt_qals WHERE ...

LOOP AT lt_qals ASSIGNING <fs_qals>.
  AUTHORITY-CHECK OBJECT 'Q_INSPTYPE'
    ID 'WERKS'     FIELD <fs_qals>-werk
    ID 'QPRUEFART' FIELD <fs_qals>-art.
  IF sy-subrc <> 0.
    DELETE lt_qals.   " 无权限行剔除
  ENDIF.
ENDLOOP.

5.2 模式二:DB 层 RANGE 限制(大数据量必用)

abap 复制代码
" 先把用户有权限的工厂/检验类型构建成 RANGE,加到 WHERE
SELECT werks, qpruefart FROM agr_xxx ... INTO ...  " 按用户授权展开

SELECT * FROM qals INTO TABLE @lt_qals
  WHERE werks IN @lr_werks
    AND art   IN @lr_art.

5.3 字段名陷阱

检验类型在表 QALS/屏幕里叫 ART ,但在授权对象里字段名是 QPRUEFART 。写 ID 'ART' 校验会永远失效 ,必须用 QPRUEFART

5.4 sy-subrc 铁律

abap 复制代码
AUTHORITY-CHECK OBJECT 'Q_INSPTYPE'
  ID 'WERKS'     FIELD in_qals_imp-werk
  ID 'QPRUEFART' FIELD in_qals_imp-art.

IF sy-subrc <> 0.          " 只用 <> 0 拦截,别只写 = 4
  " 4  = 无此授权值
  " 12 = 用户根本没有该对象
  " 24 = 用户 profile 里未包含
  msgty = 'E'.
  msgtx = '当前用户无该工厂/检验类型建批权限'.
  RETURN.
ENDIF.

漏判 12/24 是自定义程序最常见的安全漏洞 ------用户根本没有 Q_INSPTYPE 时,sy-subrc = 12,若只判 = 4,校验会直接放行。
#mermaid-svg-kumWZkOIRH262bJS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kumWZkOIRH262bJS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kumWZkOIRH262bJS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kumWZkOIRH262bJS .error-icon{fill:#552222;}#mermaid-svg-kumWZkOIRH262bJS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kumWZkOIRH262bJS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kumWZkOIRH262bJS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kumWZkOIRH262bJS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kumWZkOIRH262bJS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kumWZkOIRH262bJS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kumWZkOIRH262bJS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kumWZkOIRH262bJS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kumWZkOIRH262bJS .marker.cross{stroke:#333333;}#mermaid-svg-kumWZkOIRH262bJS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kumWZkOIRH262bJS p{margin:0;}#mermaid-svg-kumWZkOIRH262bJS .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kumWZkOIRH262bJS .cluster-label text{fill:#333;}#mermaid-svg-kumWZkOIRH262bJS .cluster-label span{color:#333;}#mermaid-svg-kumWZkOIRH262bJS .cluster-label span p{background-color:transparent;}#mermaid-svg-kumWZkOIRH262bJS .label text,#mermaid-svg-kumWZkOIRH262bJS span{fill:#333;color:#333;}#mermaid-svg-kumWZkOIRH262bJS .node rect,#mermaid-svg-kumWZkOIRH262bJS .node circle,#mermaid-svg-kumWZkOIRH262bJS .node ellipse,#mermaid-svg-kumWZkOIRH262bJS .node polygon,#mermaid-svg-kumWZkOIRH262bJS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kumWZkOIRH262bJS .rough-node .label text,#mermaid-svg-kumWZkOIRH262bJS .node .label text,#mermaid-svg-kumWZkOIRH262bJS .image-shape .label,#mermaid-svg-kumWZkOIRH262bJS .icon-shape .label{text-anchor:middle;}#mermaid-svg-kumWZkOIRH262bJS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kumWZkOIRH262bJS .rough-node .label,#mermaid-svg-kumWZkOIRH262bJS .node .label,#mermaid-svg-kumWZkOIRH262bJS .image-shape .label,#mermaid-svg-kumWZkOIRH262bJS .icon-shape .label{text-align:center;}#mermaid-svg-kumWZkOIRH262bJS .node.clickable{cursor:pointer;}#mermaid-svg-kumWZkOIRH262bJS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kumWZkOIRH262bJS .arrowheadPath{fill:#333333;}#mermaid-svg-kumWZkOIRH262bJS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kumWZkOIRH262bJS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kumWZkOIRH262bJS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kumWZkOIRH262bJS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kumWZkOIRH262bJS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kumWZkOIRH262bJS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kumWZkOIRH262bJS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kumWZkOIRH262bJS .cluster text{fill:#333;}#mermaid-svg-kumWZkOIRH262bJS .cluster span{color:#333;}#mermaid-svg-kumWZkOIRH262bJS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kumWZkOIRH262bJS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kumWZkOIRH262bJS rect.text{fill:none;stroke-width:0;}#mermaid-svg-kumWZkOIRH262bJS .icon-shape,#mermaid-svg-kumWZkOIRH262bJS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kumWZkOIRH262bJS .icon-shape p,#mermaid-svg-kumWZkOIRH262bJS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kumWZkOIRH262bJS .icon-shape .label rect,#mermaid-svg-kumWZkOIRH262bJS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kumWZkOIRH262bJS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kumWZkOIRH262bJS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kumWZkOIRH262bJS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 0
4
12
24
AUTHORITY-CHECK 返回 sy-subrc
sy-subrc 值
✅ 通过
❌ 无此授权值
❌ 用户根本没该对象
❌ Profile 中未包含
正确做法:IF sy-subrc <> 0
全部拒绝,安全


六、QA32 的权限控制真相

/NSU53 可在打开 QA32 失败后看到实际缺哪个对象:

对象 字段 控制内容
Q_TCODE TCD = QA32 能不能进 QA32
Q_INSPTYPE WERKS + QPRUEFART 按工厂能看哪些检验类型的批(控制"工厂维度"的标准手段
Q_QM_ALL QM_WERKS + ACTVT QM 通用授权(按工厂)
Q_MATERIAL 物料授权组 按物料授权组(需 MM 主数据 QM 视图维护授权组)

标准行为 :用户没有包含在 Q_INSPTYPE 里的工厂/检验类型,其检验批在 QA32 工作清单里会被过滤掉(看不到)。

一个常见的误解 是"QA32 没法做权限,权限都做在它跳转的事务码(QA11/QA02/QE51)上"。这只对一半------QA32 确实是网关,点进去的具体动作各有独立授权检查;但 QA32 工作清单本身确实按 Q_INSPTYPE 过滤,"在 QA32 看不到某工厂的批"是标准能实现的。

标准做不到的情况 :想按物料类型/物料组/工作中心限制 QA32 看到的批,Q_INSPTYPE 不够。可选方案:

  • 用户出口 / BAdI 增强
  • Q_MATERIAL(物料授权组)+ 物料主数据维护授权组
  • 按工作中心区分

七、深入理解「一份配置两头生效」

这是本文标题中最容易被忽略但最重要的一点,值得单独展开。

7.1 门禁卡类比

想象公司有两道门:

谁装的 读卡器型号
A 门(标准程序 QA32) 物业装的 Q_INSPTYPE
B 门(Z 程序) 自己装的 也选 Q_INSPTYPE 读卡器

因为 B 门选的读卡器型号和 A 门一样,所以:

  • 人事部在系统里给员工张三办一张 Q_INSPTYPE
  • 张三同时能刷开 A 门和 B 门
  • 不需要为 B 门单独办第二张卡

如果 B 门选了另一个型号的读卡器 (比如自建的 Z_INSPTYPE),则需要:

  • 为张三办两张卡
  • 每次员工入职/调岗/离职,都要同步维护两套
  • 忘了维护任何一套,就出现"A 门能进、B 门进不去"或反过来的割裂

7.2 具体对比

假设公司有 3 个工厂:1000、2000、3000。用户张三只能看工厂 1000 的检验批。

✅ 好做法 :PFCG 里配一次 Q_INSPTYPE,QA32 和 Z 程序同时生效。

❌ 坏做法 :Z 程序用自建 Z_INSPTYPE,PFCG 要配两次,容易割裂。

对比项 用标准对象(Q_INSPTYPE) 用自建对象(Z_INSPTYPE)
PFCG 配置次数 1 次 2 次
两边权限是否一致 自动一致 可能不一致
员工调岗维护 改 1 处 改 2 处
Basis 沟通成本 低(SU24 已有建议值) 高(要额外维护 SU24)

前提:标准授权对象能覆盖业务需求。当它管不了物料类型/工作中心这类维度时,才考虑自建对象或增强方案。


八、延伸场景:只配 Z 事务码、不配 QA32 安全吗?

这是一个非常实际的权限设计场景。答案需要从两层权限的角度来看。

8.1 结论先行

问题 答案
用户能不能进 QA32? 不能(S_TCODE 拦截)
用户能不能用自建 Z 程序? (S_TCODE 配了 Z 事务码)
Z 程序能看到的数据 = QA32 能看到的数据吗? ⚠️ 不一定,取决于 Z 程序检查了什么数据权限对象
这算不算"绕过 QA32"? 🚨 可能是安全漏洞,视场景而定

8.2 两层权限的分工

#mermaid-svg-Gra4S2tAMDKDk7gL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Gra4S2tAMDKDk7gL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Gra4S2tAMDKDk7gL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Gra4S2tAMDKDk7gL .error-icon{fill:#552222;}#mermaid-svg-Gra4S2tAMDKDk7gL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Gra4S2tAMDKDk7gL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Gra4S2tAMDKDk7gL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Gra4S2tAMDKDk7gL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Gra4S2tAMDKDk7gL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Gra4S2tAMDKDk7gL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Gra4S2tAMDKDk7gL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Gra4S2tAMDKDk7gL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Gra4S2tAMDKDk7gL .marker.cross{stroke:#333333;}#mermaid-svg-Gra4S2tAMDKDk7gL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Gra4S2tAMDKDk7gL p{margin:0;}#mermaid-svg-Gra4S2tAMDKDk7gL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Gra4S2tAMDKDk7gL .cluster-label text{fill:#333;}#mermaid-svg-Gra4S2tAMDKDk7gL .cluster-label span{color:#333;}#mermaid-svg-Gra4S2tAMDKDk7gL .cluster-label span p{background-color:transparent;}#mermaid-svg-Gra4S2tAMDKDk7gL .label text,#mermaid-svg-Gra4S2tAMDKDk7gL span{fill:#333;color:#333;}#mermaid-svg-Gra4S2tAMDKDk7gL .node rect,#mermaid-svg-Gra4S2tAMDKDk7gL .node circle,#mermaid-svg-Gra4S2tAMDKDk7gL .node ellipse,#mermaid-svg-Gra4S2tAMDKDk7gL .node polygon,#mermaid-svg-Gra4S2tAMDKDk7gL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Gra4S2tAMDKDk7gL .rough-node .label text,#mermaid-svg-Gra4S2tAMDKDk7gL .node .label text,#mermaid-svg-Gra4S2tAMDKDk7gL .image-shape .label,#mermaid-svg-Gra4S2tAMDKDk7gL .icon-shape .label{text-anchor:middle;}#mermaid-svg-Gra4S2tAMDKDk7gL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Gra4S2tAMDKDk7gL .rough-node .label,#mermaid-svg-Gra4S2tAMDKDk7gL .node .label,#mermaid-svg-Gra4S2tAMDKDk7gL .image-shape .label,#mermaid-svg-Gra4S2tAMDKDk7gL .icon-shape .label{text-align:center;}#mermaid-svg-Gra4S2tAMDKDk7gL .node.clickable{cursor:pointer;}#mermaid-svg-Gra4S2tAMDKDk7gL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Gra4S2tAMDKDk7gL .arrowheadPath{fill:#333333;}#mermaid-svg-Gra4S2tAMDKDk7gL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Gra4S2tAMDKDk7gL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Gra4S2tAMDKDk7gL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Gra4S2tAMDKDk7gL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Gra4S2tAMDKDk7gL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Gra4S2tAMDKDk7gL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Gra4S2tAMDKDk7gL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Gra4S2tAMDKDk7gL .cluster text{fill:#333;}#mermaid-svg-Gra4S2tAMDKDk7gL .cluster span{color:#333;}#mermaid-svg-Gra4S2tAMDKDk7gL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Gra4S2tAMDKDk7gL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Gra4S2tAMDKDk7gL rect.text{fill:none;stroke-width:0;}#mermaid-svg-Gra4S2tAMDKDk7gL .icon-shape,#mermaid-svg-Gra4S2tAMDKDk7gL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Gra4S2tAMDKDk7gL .icon-shape p,#mermaid-svg-Gra4S2tAMDKDk7gL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Gra4S2tAMDKDk7gL .icon-shape .label rect,#mermaid-svg-Gra4S2tAMDKDk7gL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Gra4S2tAMDKDk7gL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Gra4S2tAMDKDk7gL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Gra4S2tAMDKDk7gL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 权限控制两层
第一层:S_TCODE

能不能启动这个事务码
第二层:数据权限对象

如 Q_INSPTYPE

进去后能看到哪些数据
QA32 用 QA32

Z 程序用 ZQM_REPORT

各自独立
两边都用 Q_INSPTYPE

→ 数据权限一致 ✅
Z 程序用自建对象

→ 数据权限可能不一致 🚨

关键点S_TCODE 只管"能不能进去",Q_INSPTYPE 管"进去后能看到哪些数据",两者互不干涉。

8.3 两种典型情况

情况 A:Z 程序用标准对象 Q_INSPTYPE(安全)

复制代码
S_TCODE:
  ✅ ZQM_REPORT
  ❌ QA32(故意不给)

数据权限:
  ✅ Q_INSPTYPE  WERKS = 1000, QPRUEFART = 01,02
  • 用户进不了 QA32 ✅
  • 用户用 Z 程序,只看到工厂 1000 的数据 ✅
  • 数据权限由 Q_INSPTYPE 统一控制 ✅

情况 B:Z 程序用自建对象且全放开(危险)

复制代码
S_TCODE:
  ✅ ZQM_REPORT
  ❌ QA32

数据权限:
  ✅ Z_QM_ALL   ALL = 'X'   ← 自建对象,全放开
  • 用户进不了 QA32(假象)✅
  • 用户通过 Z 程序看到了工厂 2000 的全量数据 🚨
  • 权限设计被绕过 🚨
  • 审计/合规风险 🚨

8.4 判断标准

判断维度 安全 危险
Z 程序用什么数据对象? 标准对象(Q_INSPTYPE) 自建对象(Z_*)或不用
过滤逻辑和 QA32 一致吗? 一致 不一致或更宽松
用户能看到的数据范围 ⊆ QA32 的范围 ⊃ QA32 的范围
是否经过安全审核

一句话:Z 程序的数据权限范围 ≤ QA32 的范围 → 安全;反之 → 安全漏洞。

8.5 别忽略"其他入口"

即使不给用户 QA32 的 S_TCODE,用户仍可能通过其他入口访问 QA32 数据:

潜在入口 前提条件 风险
SE38 → 运行标准程序 用户有 S_DEVELOP
SE16/SE16N → 直接查 QALS 用户有 S_TABU_DIS 的 QALS 授权组
从其他事务码跳转 S_TCODE 依然会检查
用 SM30 维护视图 用户有 S_TABU_DIS
通过 BI/报表工具 取决于工具权限

因此,光不给 S_TCODE 是不够的,还要在表级用 S_TABU_DIS(授权组)防护。


九、避坑清单

复制代码
□ 1. 只用 IF sy-subrc <> 0 拦截,别只写 = 4。漏 12/24 等于权限白配。

□ 2. 大数据量用"授权 RANGE + WHERE",别 SELECT 后逐行 AUTHORITY-CHECK + DELETE。
     后者会把无权限行读进内表(数据泄露窗口)且性能差。

□ 3. 选择屏幕校验(AT SELECTION-SCREEN)不能单独用------用户全选 * 就绕过,
     只能作为友好提示,真正拦截面在取数/处理时。

□ 4. 两层防护:代码里 AUTHORITY-CHECK(控业务维度)+ 表上 S_TABU_DIS
     (防用户绕过程序去 SE16 看整张表)。

□ 5. 对齐标准、复用同一对象:自定义建批程序用 Q_INSPTYPE,QA32 也认它
     → 一份 PFCG 授权两端同时生效。

□ 6. 自定义事务码记得去 SU24 维护检查建议值,让 Basis 建角色时自动带出。

□ 7. 配完三步别漏:生成 → 用户比较 → 重登;用 /NSU53 验证、SU56 查缓冲。

□ 8. 行级/数据级安全别想当然:BW 分析授权自定义程序直读不过滤,
     必须显式调用带授权的 API。

□ 9. 只配 Z 事务码、不配 QA32 → Z 程序必须用标准对象 Q_INSPTYPE 检查,
     否则就是绕过标准权限的安全漏洞。

□ 10. 字段名陷阱:检验类型在表里叫 ART,在授权对象里叫 QPRUEFART。

十、总结

机制同源、对象通用、生命周期相同------这是自定义与标准权限控制的共同点。

真正的分水岭是"谁触发检查":

  • 标准:由 SAP 写死自动执行
  • 自定义 :由开发者显式写 AUTHORITY-CHECK,不写就不查

#mermaid-svg-vKHL0gDEdg1CRM0h{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vKHL0gDEdg1CRM0h .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vKHL0gDEdg1CRM0h .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vKHL0gDEdg1CRM0h .error-icon{fill:#552222;}#mermaid-svg-vKHL0gDEdg1CRM0h .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vKHL0gDEdg1CRM0h .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vKHL0gDEdg1CRM0h .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vKHL0gDEdg1CRM0h .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vKHL0gDEdg1CRM0h .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vKHL0gDEdg1CRM0h .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vKHL0gDEdg1CRM0h .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vKHL0gDEdg1CRM0h .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vKHL0gDEdg1CRM0h .marker.cross{stroke:#333333;}#mermaid-svg-vKHL0gDEdg1CRM0h svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vKHL0gDEdg1CRM0h p{margin:0;}#mermaid-svg-vKHL0gDEdg1CRM0h .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vKHL0gDEdg1CRM0h .cluster-label text{fill:#333;}#mermaid-svg-vKHL0gDEdg1CRM0h .cluster-label span{color:#333;}#mermaid-svg-vKHL0gDEdg1CRM0h .cluster-label span p{background-color:transparent;}#mermaid-svg-vKHL0gDEdg1CRM0h .label text,#mermaid-svg-vKHL0gDEdg1CRM0h span{fill:#333;color:#333;}#mermaid-svg-vKHL0gDEdg1CRM0h .node rect,#mermaid-svg-vKHL0gDEdg1CRM0h .node circle,#mermaid-svg-vKHL0gDEdg1CRM0h .node ellipse,#mermaid-svg-vKHL0gDEdg1CRM0h .node polygon,#mermaid-svg-vKHL0gDEdg1CRM0h .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vKHL0gDEdg1CRM0h .rough-node .label text,#mermaid-svg-vKHL0gDEdg1CRM0h .node .label text,#mermaid-svg-vKHL0gDEdg1CRM0h .image-shape .label,#mermaid-svg-vKHL0gDEdg1CRM0h .icon-shape .label{text-anchor:middle;}#mermaid-svg-vKHL0gDEdg1CRM0h .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vKHL0gDEdg1CRM0h .rough-node .label,#mermaid-svg-vKHL0gDEdg1CRM0h .node .label,#mermaid-svg-vKHL0gDEdg1CRM0h .image-shape .label,#mermaid-svg-vKHL0gDEdg1CRM0h .icon-shape .label{text-align:center;}#mermaid-svg-vKHL0gDEdg1CRM0h .node.clickable{cursor:pointer;}#mermaid-svg-vKHL0gDEdg1CRM0h .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vKHL0gDEdg1CRM0h .arrowheadPath{fill:#333333;}#mermaid-svg-vKHL0gDEdg1CRM0h .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vKHL0gDEdg1CRM0h .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vKHL0gDEdg1CRM0h .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vKHL0gDEdg1CRM0h .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vKHL0gDEdg1CRM0h .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vKHL0gDEdg1CRM0h .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vKHL0gDEdg1CRM0h .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vKHL0gDEdg1CRM0h .cluster text{fill:#333;}#mermaid-svg-vKHL0gDEdg1CRM0h .cluster span{color:#333;}#mermaid-svg-vKHL0gDEdg1CRM0h div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vKHL0gDEdg1CRM0h .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vKHL0gDEdg1CRM0h rect.text{fill:none;stroke-width:0;}#mermaid-svg-vKHL0gDEdg1CRM0h .icon-shape,#mermaid-svg-vKHL0gDEdg1CRM0h .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vKHL0gDEdg1CRM0h .icon-shape p,#mermaid-svg-vKHL0gDEdg1CRM0h .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vKHL0gDEdg1CRM0h .icon-shape .label rect,#mermaid-svg-vKHL0gDEdg1CRM0h .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vKHL0gDEdg1CRM0h .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vKHL0gDEdg1CRM0h .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vKHL0gDEdg1CRM0h :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 自定义程序三大风险
① 漏写检查
② = 4 漏判 12/24
③ SELECT 绕过 S_TABU_DIS
程序门户大开
校验形同虚设
数据泄露风险

三点核心结论

  1. 自定义程序中的 AUTHORITY-CHECK 不会影响标准事务码的行为。两套程序各自独立运行。
  2. 想让两者一致受控,正确做法是统一使用标准授权对象 (如 Q_INSPTYPE),PFCG 配一份,两端自动同时生效。
  3. 只配 Z 事务码、不配 QA32 时 ,只要 Z 程序用标准对象 Q_INSPTYPE 检查,就是安全的;用自建对象或干脆不检查,就是通过 Z 程序绕过标准权限的安全漏洞。

核心一句话

不给 QA32 的 S_TCODE,只是"堵住了大门";数据权限的"窗户"是否关好,取决于 Z 程序有没有检查 Q_INSPTYPE


附:本文归档说明

本文源自一次 QM 检验批自建程序的权限设计讨论,涉及检验类型字段名 QPRUEFART 的陷阱、QA32 与自定义程序权限边界等实战话题,连同前序的《一次 ASSIGN_TYPE_CONFLICT 排查记》一并归档,供团队内部参考。


💬 你在自定义程序里写过 AUTHORITY-CHECK 吗?有没有因为漏判 sy-subrc = 12 而被安全审计抓过?有没有遇到过"用户进不了标准事务码,但通过自建程序看到了全量数据"的情况?欢迎分享你的权限设计经验。

相关推荐
天天喝旺仔2 小时前
MySQL索引优化实战:B+Tree原理、索引失效与覆盖索引调优
数据库·sql·mysql·性能优化
hanchenxing2 小时前
向量数据库备份恢复实战:从快照到时间点回滚的优化方案向量数据库
性能优化·备份恢复
打工仔折腾 AI2 小时前
Pascal Editor 本地部署实战:Bun 启动 WebGPU 3D 编辑器并解决公网访问报错
人工智能·后端·python·性能优化
贾伟康2 小时前
【HarmonyOS 7新能力|038】游戏快启工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·游戏开发·软件架构
林川~012 小时前
Unity 反射(Reflection)从原理到实战:一篇讲透原理、用法、实战案例与性能优化
面试·性能优化·反射·il2cpp·type
HwJack203 小时前
【HarmonyOS开发小实践】ArkUI 交互事件与手势:从触摸到组合手势
ui·华为·性能优化·harmonyos
hanchenxing3 小时前
日志采集日志采集性能优化:从正则解析到 Grok 与 JSON 的双级加速
性能优化·filebeat
贾伟康3 小时前
【HarmonyOS 7新能力|039】冷启网络预建链工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·软件架构·网络优化
政企项目老覃19 小时前
边缘 AI 推理部署:安防零售场景下的模型裁剪与端侧落地实践
人工智能·程序人生·算法·性能优化·vllm