SAP-ABAP: SAP 自开发报表程序权限控制实战:从事务码到数据行级的安全防护
SAP 自开发报表程序权限控制实战从事务码到数据行级的安全防护作者爱喝水的鱼丶适用系统SAP ECC / S/4HANA关键词权限对象、AUTHORITY-CHECK、S_TCODE、公司代码、字段级权限、行级权限在 SAP 系统中自开发报表承载了大量关键业务数据的查询与展示。如果权限控制不到位轻则导致越权查看数据重则引发审计合规风险。本文将从事务码入口权限、数据行级权限公司代码/工厂、字段级权限、操作权限四个层级系统讲解如何在自开发报表程序中实施严谨的权限控制并提供可直接复用的代码模板与配置步骤。一、权限控制体系总览一个完善的自开发报表权限模型应包含以下层级┌─────────────────────────────────────────────┐ │ 报表程序权限控制 │ ├─────────────────────────────────────────────┤ │ L1事务码权限谁能运行报表 │ │ L2数据行级权限能查看哪些公司/工厂的数据 │ │ L3字段级权限能看到金额、成本等敏感列吗 │ │ L4操作权限能否导出、编辑、审批 │ └─────────────────────────────────────────────┘实现上述权限控制通常需要以下 SAP 技术标准权限对象S_TCODE、S_PROGRAM等自定义权限对象SU21按公司代码、工厂、利润中心等定义的授权字段AUTHORITY-CHECK语句在 ABAP 代码中执行权限检查动态 ALV 字段目录根据权限结果控制LVC_T_FCAT是否包含敏感列事件处理器toolbar根据权限启用/禁用操作按钮二、事务码权限控制L12.1 标准权限对象S_TCODE每个自开发报表都应分配一个事务码通过 SE93 创建。用户在菜单中点击事务码时系统会自动检查S_TCODE对象确保用户有执行该事务码的权限。配置步骤事务码SE93输入自开发程序名创建事务码如ZSD001在 PFCG 角色中添加该事务码并生成参数文件系统自动生效无需在代码中显式检查S_TCODE2.2 程序内部双重保险虽然事务码本身已提供访问控制但在报表程序内部显式检查S_TCODE可以防止通过SE38直接执行程序绕过权限。建议在START-OF-SELECTION或专门的授权检查模块开头执行FORM check_tcode_authority. AUTHORITY-CHECK OBJECT S_TCODE ID TCODE FIELD ZSD001 本程序对应的事务码 ID ACTVT FIELD 16. 16 执行 IF sy-subrc 0. MESSAGE 您没有执行此报表的权限 TYPE E. ENDIF. ENDFORM.注意S_TCODE的ACTVT通常建议使用16执行这是标准的事务码执行活动。三、数据行级权限公司代码、工厂等L2这是自开发报表中最核心的权限控制。我们需要定义自定义权限对象并在代码中使用AUTHORITY-CHECK过滤数据。3.1 创建自定义权限对象以“公司代码”为例创建一个权限对象Z_BUKRS。步骤事务码SU21选择“权限对象” → “创建”输入对象名Z_BUKRS描述“公司代码权限”添加两个权限字段ACTVT活动数据元素ACTVT必填用于区分显示03、修改02等BUKRS公司代码数据元素BUKRS必填支持多值保存并激活类似地可以创建Z_WERKS工厂、Z_PRCTR利润中心等。3.2 在 PFCG 角色中维护权限值在角色PFCG的权限数据中找到刚刚创建的对象Z_BUKRS维护具体的授权值例如ACTVT 03显示BUKRS 1000, 2000然后分配给用户。3.3 ABAP 代码中实施行级过滤方案一使用AUTHORITY-CHECK逐条过滤适合小数据量FORM filter_by_bukrs CHANGING ct_data TYPE tt_sales_data. DATA lv_auth TYPE c LENGTH 1. LOOP AT ct_data INTO DATA(ls_data). AUTHORITY-CHECK OBJECT Z_BUKRS ID ACTVT FIELD 03 ID BUKRS FIELD ls_data-bukrs. IF sy-subrc 0. DELETE ct_data WHERE bukrs ls_data-bukrs. ENDIF. ENDLOOP. IF ct_data IS INITIAL. MESSAGE 您没有查看任何公司代码数据的权限 TYPE E. ENDIF. ENDFORM.方案二先获取授权值列表再在 SQL 中过滤推荐性能更好标准 SAP 并不直接提供获取用户所有授权值的函数但可以通过构建 RANGES 表结合AUTHORITY-CHECK遍历可能的公司代码列表来获得授权值。或者将常用公司代码硬编码在配置表中再与权限值比对。一个更通用的方法是使用函数SUSR_USER_AUTH_FOR_OBJ_GET来获取用户拥有的权限值。FORM get_authorized_bukrs CHANGING ct_bukrs TYPE RANGE OF bukrs. DATA: lt_user_auth TYPE TABLE OF usr_auth_t, ls_range LIKE LINE OF ct_bukrs. CALL FUNCTION SUSR_USER_AUTH_FOR_OBJ_GET EXPORTING object Z_BUKRS user sy-uname TABLES auth_values lt_user_auth. LOOP AT lt_user_auth INTO DATA(ls_auth). 注意该函数返回的权限值为内部格式需解析 简单场景可手动维护公司代码清单 ENDLOOP. ENDFORM.推荐简化做法如果在项目中公司代码数量有限可以维护一个配置表ZCFI_BUKRS然后在 PFCG 中为每个公司代码单独设置权限。在报表中直接读取该配置表与用户权限比对。更简单直接的工厂权限标准对象也可以直接使用M_MATE_WRK物料工厂或M_EKPO_WRK采购订单工厂等但这些都是专用的。对于通用报表通常还是自定义对象最灵活。实际开发中我们通常在 SQL 查询的 WHERE 条件中加入授权公司代码范围这就要求我们将用户的授权公司代码事先填充到一个 RANGE 表中。实现方法可以调用函数AUTHORITY_CHECK_TCODE结合遍历或使用更高级的类CL_AUTH_OBJECTS_TO_SQLS/4HANA 1909将授权对象转换为 SQL WHERE 条件。示例使用CL_AUTH_OBJECTS_TO_SQLS/4HANA 高版本推荐DATA(lo_auth_sql) cl_auth_objects_to_sqlcreate_for_open_sql( ). lo_auth_sql-add_authorization_object( i_auth_object Z_BUKRS i_activity 03 ). lo_auth_sql-build( IMPORTING et_where DATA(lt_where) ). lt_where 可直接用于 SELECT ... WHERE (lt_where) 的动态条件如果你的系统版本还不支持该新功能仍可使用循环检查方式但要注意性能。四、字段级权限隐藏敏感列L3业务部门常常要求普通用户看不到金额、成本、利润等敏感字段。这可以通过自定义权限对象如Z_SD_FIELD包含FIELDNAME字段实现然后在 ALV 字段目录构建时动态添加。权限对象设计Z_SD_FIELDACTVT03显示FIELDNAME例如NETWR金额、WERKS工厂代码实现DATA gv_show_netwr TYPE abap_bool. FORM check_field_authority. AUTHORITY-CHECK OBJECT Z_SD_FIELD ID ACTVT FIELD 03 ID FIELDNAME FIELD NETWR. gv_show_netwr COND #( WHEN sy-subrc 0 THEN abap_true ELSE abap_false ). ENDFORM. FORM prepare_fieldcat. 公共字段... IF gv_show_netwr abap_true. INSERT VALUE #( fieldname NETWR coltext 金额 col_pos 10 outputlen 18 do_sum abap_true cfieldname WAERS datatype CURR ) INTO TABLE gt_fieldcat. ENDIF. ENDFORM.这样无权限用户的 ALV 报表中根本不会出现“金额”列实现了字段级安全。五、操作权限控制导出、编辑等按钮L4工具栏上的“导出”、“审批”、“编辑”等按钮应根据权限动态显隐或禁用。权限对象Z_SD_ACT包含ACTVT和ACTION如EXPORT、EDIT。代码实现METHOD handle_toolbar. DATA: ls_btn TYPE stb_button. IF gv_can_export abap_true. 由权限检查得到 ls_btn-function EXPORT. ls_btn-icon icon_download. ls_btn-text 导出. APPEND ls_btn TO e_object-mt_toolbar. ENDIF. IF gv_can_edit abap_true. ls_btn-function EDIT. ls_btn-icon icon_change. ls_btn-text 编辑. APPEND ls_btn TO e_object-mt_toolbar. ENDIF. ENDMETHOD.同时在handle_user_command中对应EXPORT、EDIT的代码前也最好再次进行权限校验防止通过直接调用 RFC 等方式绕过。六、完整示例结合公司代码权限与字段权限的销售报表以下是一个简化的销售订单报表演示如何整合事务码权限、公司代码行级权限和金额字段级权限。REPORT zsd_authorized_report. TYPES: BEGIN OF ty_sales, vbeln TYPE vbak-vbeln, bukrs TYPE vbak-bukrs, 假设VBAK中有公司代码字段实际需关联 netwr TYPE vbap-netwr, waers TYPE vbak-waers, kunnr TYPE vbak-kunnr, END OF ty_sales. DATA: gt_data TYPE TABLE OF ty_sales, gt_fieldcat TYPE lvc_t_fcat, gs_layout TYPE lvc_s_layo, go_alv TYPE REF TO cl_gui_alv_grid. 授权标志 DATA: gv_show_netwr TYPE abap_bool. START-OF-SELECTION. PERFORM check_tcode_authority. PERFORM check_field_auth. PERFORM fetch_data_with_bukrs_auth. PERFORM prepare_fieldcat. PERFORM display_alv. FORM check_tcode_authority. AUTHORITY-CHECK OBJECT S_TCODE ID TCODE FIELD ZSD001 ID ACTVT FIELD 16. IF sy-subrc 0. MESSAGE 无事务码权限 TYPE E. ENDIF. ENDFORM. FORM check_field_auth. AUTHORITY-CHECK OBJECT Z_SD_FIELD ID ACTVT FIELD 03 ID FIELDNAME FIELD NETWR. gv_show_netwr COND #( WHEN sy-subrc 0 THEN abap_true ELSE abap_false ). ENDFORM. FORM fetch_data_with_bukrs_auth. 模拟获取授权公司代码列表实际应使用前述方法生成 RANGE DATA lr_bukrs TYPE RANGE OF bukrs. lr_bukrs VALUE #( sign I option EQ ( low 1000 ) ( low 2000 ) ). SELECT vbak~vbeln, vbak~bukrs, vbap~netwr, vbak~waers, vbak~kunnr INTO CORRESPONDING FIELDS OF TABLE gt_data FROM vbak INNER JOIN vbap ON vbak~vbeln vbap~vbeln WHERE vbak~bukrs IN lr_bukrs UP TO 1000 ROWS. ENDFORM. FORM prepare_fieldcat. INSERT VALUE #( fieldname VBELN coltext 订单号 col_pos 1 outputlen 10 ) INTO TABLE gt_fieldcat. INSERT VALUE #( fieldname BUKRS coltext 公司代码 col_pos 2 outputlen 4 ) INTO TABLE gt_fieldcat. INSERT VALUE #( fieldname KUNNR coltext 客户 col_pos 3 outputlen 10 ) INTO TABLE gt_fieldcat. IF gv_show_netwr abap_true. INSERT VALUE #( fieldname NETWR coltext 金额 col_pos 4 outputlen 18 do_sum abap_true cfieldname WAERS datatype CURR ) INTO TABLE gt_fieldcat. INSERT VALUE #( fieldname WAERS coltext 货币 col_pos 5 outputlen 5 ) INTO TABLE gt_fieldcat. ENDIF. ENDFORM. FORM display_alv. CREATE OBJECT go_container... 省略具体容器创建 go_alv-set_table_for_first_display( EXPORTING is_layout gs_layout CHANGING it_outtab gt_data it_fieldcatalog gt_fieldcat ). ENDFORM.七、权限对象配置与管理7.1 配置流程总结步骤事务码操作1. 创建权限对象SU21定义对象名和权限字段2. 创建/修改角色PFCG在“权限”标签中添加对象并维护值3. 生成参数文件PFCG保存时自动生成4. 分配用户SU01将角色分配给用户5. 代码检查程序使用 AUTHORITY-CHECK7.2 推荐的命名规范自定义权限对象Z_模块_级别如Z_FI_BUKRS、Z_MM_WERKS字段名尽量复用标准数据元素如ACTVT、BUKRS、WERKS对于操作权限字段值使用语义化名称EXPORT、EDIT、APPROVE八、总结自开发报表的权限控制应遵循“先检查再展示”的原则通过事务码权限L1、行级数据权限L2、字段级权限L3和操作权限L4四层架构实现全方位的数据安全防护。核心要点为每个自开发报表创建事务码并在代码中二次校验S_TCODE使用自定义权限对象SU21AUTHORITY-CHECK实现公司代码、工厂等行级数据过滤动态构建 ALV 字段目录根据权限结果隐藏敏感列工具栏按钮需根据操作权限动态启用/禁用利用CL_AUTH_OBJECTS_TO_SQL高版本简化行级权限的 SQL WHERE 生成权限对象的配置PFCG、SU01是代码生效的前提开发和权限管理团队需协同完成。建议在报表开发规范中强制要求所有涉及敏感数据的自开发程序必须实施上述权限控制并纳入上线前的安全检查清单。文档版本V1.0最后更新2026年7月 你在自开发报表权限控制方面遇到过哪些挑战欢迎留言交流