使用 AUTHORITY-CHECK 语句
学习目标
使用 AUTHORITY-CHECK 语句。
AUTHORITY-CHECK 语句


要显式执行权限检查,请使用 AUTHORITY-CHECK 语句。在其中,指定要检查的权限对象以及所需值。此处的 AUTHORITY-CHECK 针对对象 /DMO/TRVL 执行检查,并要求用户具有包含字段 /DMO/CNTRY 的值 US 以及字段 ACTVT 的值 03 的权限。
如何检查权限检查的结果
与 CDS 访问控制附带的已过滤权限检查不同,AUTHORITY-CHECK 语句不会阻止用户查看他们没有权限的数据。

AUTHORITY-CHECK 在系统字段 sy-subrc 中放置返回代码。通过在权限检查后立即检查 sy-subrc 的值,您可以找出检查是否成功。
如果权限检查成功,sy-subrc 的值为 0。sy-subrc 的其他值表示检查失败:
值 4 表示用户对相应对象具有权限,但不具有正确的值。
值 12 表示用户根本没有相应对象的权限。
如果权限检查失败,则必须确保用户自己无法访问数据。
在此示例中,权限检查要求用户对国家/地区 'US' 具有权限。由于我们的用户不是这种情况,因此 sy-subrc 在权限检查后不等于零。在这种情况下,应用显示文本 无权限 。
如何使用 AUTHORITY-CHECK 语句
观看此视频,了解如何使用权限检查语句。
视频:本节含 SAP 官方视频(视频 ID
1_5e81bjfl),需在 learning.sap.com 在线观看。
实施权限检查
您意识到您的代码使用户可以访问他们无权查看的数据。要修改此项,首先从定义了 CDS 访问控制的 CDS 视图实体中读取代码。然后实施显式权限检查,以便能够区分用户无权查看的数据和根本不存在的数据。
模板:
/LRN/CL_S4D401_ITS_SEC_KEY(全局类)
解决方案:
/LRN/CL_S4D401_ACS_AUTH_CHECK(全局类)
任务 1: 复制模板(可选)
复制模板类 /LRN/CL_S4D401_ITS_SEC_KEY。如果已完成上一练习,则可以跳过此任务并继续编辑类 ZCL_##_SOLUTION。
步骤
将类
/LRN/CL_S4D401_ITS_SEC_KEY复制到您自己的包中的类(建议名称:ZCL_##_SOLUTION,其中 ## 代表组编号)。在项目浏览器中,右键单击类
/LRN/CL_S4D401_ITS_SEC_KEY以打开上下文菜单。从上下文菜单中,选择复制....
在包字段中输入包的名称。在名称字段中,输入
ZCL_##_SOLUTION,其中 ## 代表组编号。选择下一步。
确认传输请求并选择完成。
激活复制。
按
Ctrl + F3激活类。
任务 2: 分析权限
从数据库表 /LRN/CARRIER 开始,找到保护承运商数据免受未授权访问的 CDS 访问控制。分析 CDS 访问控制以找出用户显示承运方数据所需的权限。
步骤
显示数据库表
/LRN/CARRIER的定义。按
Ctrl + Shift + A并在搜索字段中输入/LRN/CARRIER。选择确定。
分析此数据库表的使用位置清单。
在数据库表
/LRN/CARRIER的定义中,右键单击/lrn/carrier并选择获取调用清单。或者,单击/lrn/carrier并按Ctrl + Shift + G。在选择对象类型对话框中,确保至少选择对象类型**
数据定义**,然后选择完成。在编辑器下方的搜索视图中,选择漏斗图标以打开过滤器对话框。
将光标置于对象类型字段中,然后按 **
Ctrl + 空格**打开值帮助对话框。从建议列表中选择 DDLS/DF(数据定义),然后选择应用。
分析 CDS 视图 **
/LRN/I_CARRIER**的使用位置清单。在搜索视图中,右键单击 /LRN/I_CARRIER(数据定义),然后选择获取使用位置清单。或者,单击 */LRN/I_CARRIER(数据定义)*并按
Ctrl + Shift + G。在选择对象类型对话框中,确保至少选择对象类型**
访问控制**,然后选择完成。如果编辑器下方的搜索视图显示的搜索结果过多,请选择漏斗图标以打开过滤器对话框。将光标置于对象类型字段中,然后按 **
Ctrl + 空格**打开值帮助对话框。从建议清单中选择 DCLS/DL(访问控制),然后选择应用。打开访问控制
/LRN/I_CARRIER的定义。在搜索视图中,双击 /LRN/I_CARRIER(访问控制)。
权限对象名称是函数
pfcg_auth的第一个输入参数。其他输入参数为权限对象的权限字段提供值。
打开权限对象
/LRN/CARR的定义以分析活动值的含义。按住
Ctrl键并单击函数pfcg_auth调用中的/LRN/CARR。允许的活动下列出可能的活动值。
任务 3: 使用 CDS 访问控制
在本地类 LCL_CARRIER 的**构造函数**方法中,将数据库表 /LRN/CARRIER 替换为 CDS 视图 /LRN/I_CARRIER,该视图受 CDS 访问控制 /LRN/I_CARRIER 保护。使用不同的载体标识作为构造函数输入测试代码。
步骤
打开局部类
LCL_CARRIER的**构造函数**方法的实施。返回到全局类
ZCL_##_SOLUTION的代码,其中 ## 是您的组编号。在 大纲 视图中展开 ZCL_##_SOLUTION→LCL_CARRIER ,然后单击 CONSTRUCTOR 。
调整 SELECT 语句。在 FROM 子句中,将数据库表
/LRN/CARRIER替换为上述 CDS 视图。如下调整代码:
SELECT SINGLE
* FROM /lrn/carrier
FROM /LRN/I_Carrier
修复语法错误。将表字段名称替换为相应的 CDS 视图元素名称。
如下调整代码:
* SELECT SINGLE
* FROM /lrn/carrier
* FIELDS concat_with_space( carrier_id, name, 1 ), currency_code
* WHERE carrier_id = @i_carrier_id
* INTO ( @me->name, @me->currency_code ).
SELECT SINGLE
FROM /LRN/I_Carrier
FIELDS concat_with_space( AirlineID, Name, 1 ), CurrencyCode
WHERE AirlineID = @i_carrier_id
INTO ( @me->name, @me->currency_code ).
以控制台应用形式激活并测试全局类。
按
Ctrl + F3。按
F9。在全局类中,将本地常量
c_carrier_id的值更改为UA。切换到全局类标签。
如下调整代码:
* CONSTANTS c_carrier_id TYPE /dmo/carrier_id VALUE 'LH'.
CONSTANTS c_carrier_id TYPE /dmo/carrier_id VALUE 'UA'.
以控制台应用形式激活并测试全局类。
按
Ctrl + F3。按
F9。
任务 4: 实施 AUTHORITY-CHECK 语句
在本地类 LCL_CARRIER 的**构造函数**方法中,如果航班载体存在但用户无权使用此运输公司,则实施 AUTHORITY-CHECK 语句并引发异常 CX_ABAP_AUTH_CHECK_EXCEPTION。
步骤
打开局部类
LCL_CARRIER的**构造函数**方法的实施。确保已在编辑器中打开全局类
ZCL_##_SOLUTION,其中 ## 是您的组编号。在 大纲 视图中展开 ZCL_##_SOLUTION→LCL_CARRIER ,然后单击 CONSTRUCTOR 。
调整 SELECT 语句以再次从数据库表
/LRN/CARRIER中读取。如下调整代码:
* SELECT SINGLE
* FROM /LRN/I_Carrier
* FIELDS concat_with_space( AirlineID, Name, 1 ), CurrencyCode
* WHERE AirlineID = @i_carrier_id
* INTO ( @me->name, @me->currency_code ).
SELECT SINGLE
FROM /lrn/carrier
FIELDS concat_with_space( carrier_id, name, 1 ), currency_code
WHERE carrier_id = @i_carrier_id
INTO ( @me->name, @me->currency_code ).
实施在读取访问成功时执行的 AUTHORITY-CHECK 语句,即未引发异常 CX_ABAP_INVALID_VALUE。使用上面找到的权限对象、权限字段和值。
如下调整代码:
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.
AUTHORITY-CHECK
OBJECT '/LRN/CARR'
ID '/LRN/CARR' FIELD i_carrier_id
ID 'ACTVT' FIELD '03'.
IF sy-subrc <> 0.
ENDIF.
如果用户没有请求的航空公司标识的显示权限,则引发异常
CX_ABAP_AUTH_CHECK_EXCEPTION。如下调整代码:
AUTHORITY-CHECK
OBJECT '/LRN/CARR'
ID '/LRN/CARR' FIELD i_carrier_id
ID 'ACTVT' FIELD '03'.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_auth_check_exception.
ENDIF.
使用快速修复将异常
CX_ABAP_AUTH_CHECK_EXCEPTION添加到**构造方法**定义的 RAISING 子句中。在 RAISE EXCEPTION 语句中,单击
cx_abap_auth_check_exception并按Ctrl + 1。或者,选择具有语法警告的代码行左侧的灯泡图标。从建议的快速修复列表中,选择添加引发声明。
因此,**
构造函数**方法的定义现在应如下所示:
METHODS constructor
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
RAISING
cx_abap_invalid_value
cx_abap_auth_check_exception.
在全局类中,使用新异常
CX_ABAP_AUTH_CHECK_EXCEPTION的 CATCH 块扩展 TRY…ENDTRY 控制结构。发布合适的文本以指示用户无权显示运输公司。如下调整代码:
TRY.
DATA(carrier) = NEW lcl_carrier( i_carrier_id = c_carrier_id ).
out->write( name = `Carrier Overview`
data = carrier->get_output( ) ).
CATCH cx_abap_invalid_value.
out->write( |Carrier { c_carrier_id } does not exist| ).
CATCH cx_abap_auth_check_exception.
out->write( |No authorization to display carrier { c_carrier_id }| ).
ENDTRY.
同样,在本地单元测试类的
class_setup方法中扩展 TRY…ENDTRY 控制结构。使用与异常CX_ABAP_INVALID_VALUE的捕获块中相同的实施。
注意
这只是一个解决方法。稍后,在本课程中,您将了解如何处理同一捕获块中的多个异常。
如下调整代码:
TRY.
the_carrier = NEW lcl_carrier( i_carrier_id = some_flight_data-carrier_id ).
CATCH cx_abap_invalid_value.
cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ).
CATCH cx_abap_auth_check_exception.
cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ).
ENDTRY.
以控制台应用形式激活并测试全局类。确保您的代码在控制台上显示新文本:无权显示运输公司 UA。
按
Ctrl + F3。按
F9。在全局类中,将本地常量
c_carrier_id的值更改回LH。切换到全局类标签。
如下调整代码:
* CONSTANTS c_carrier_id TYPE /dmo/carrier_id VALUE 'UA'.
CONSTANTS c_carrier_id TYPE /dmo/carrier_id VALUE 'LH'.
以控制台应用形式激活并测试全局类。确保代码像以前一样显示承运商和航班详细信息。
按
Ctrl + F3。按
F9。