개요 및 이 글의 목표
SAP Fiori 앱을 열었을 때 "권한이 없다"는 메시지 대신 빈 화면이나 일부 데이터만 노출되는 경험을 한 적이 있을 것입니다. 이는 Fiori 아키텍처가 여러 계층(Launchpad → ICF → OData → CDS → DB)에서 각각 다른 권한 체크를 수행하기 때문입니다. 이 글에서는 SalesOrder 관리 앱을 예시로 삼아 권한 흐름의 사각지대와 이를 메우는 실전 설계를 다룹니다.
배경 지식 정리
이 글은 SAP S/4HANA 2022 이상 또는 SAP NetWeaver AS ABAP 7.55+ 환경을 전제로 합니다. 독자는 SAP GUI에서 SU01/PFCG 트랜잭션을 다룬 경험이 있고, ABAP 기본 문법(SELECT, AUTHORITY-CHECK)과 CDS View 개념을 알고 있어야 합니다.
실행 환경 및 사전 준비
- SICF: ICF 서비스 노드 활성화·인증 방식 설정
- PFCG: 역할 정의, Authorization Object 유지
- SU53: 마지막 권한 체크 실패 조회
- /IWFND/MAINT_SERVICE: Frontend Gateway 서비스 등록
- /IWFND/ERROR_LOG, /IWBEP/ERROR_LOG: OData 런타임 오류 로그
- ST01 / ST05: 권한 트레이스, SQL·RFC 트레이스
- ADT (ABAP Development Tools) 3.32+: CDS DCL 편집
핵심 개념: 4계층 권한 파이프라인
Fiori 앱 요청은 브라우저에서 백엔드까지 다음 순서로 흐릅니다. 각 계층은 독립적으로 통과 여부를 판단하며, 하나라도 "묵시적 허용"이 걸려 있으면 권한 구멍이 됩니다.
- Launchpad 타일 노출: PFCG 역할에 Catalog/Group이 할당되어야 타일이 보입니다. 타일이 보이지 않는다고 실제 데이터 접근이 막힌 것은 아닙니다.
- ICF 노드 인증: SICF에서
/sap/opu/odata/sap/ZAPI_SALES_ORDER_SRV같은 서비스 경로가 활성화되고 로그온 방식이 지정됩니다. - Gateway 서비스 레벨:
/IWFND/MAINT_SERVICE에서 System Alias와 함께 등록되고, 서비스 자체 S_SERVICE 체크가 통과되어야 합니다. - 비즈니스 로직 레벨: 엔티티셋 CRUD, CDS DCL, ABAP AUTHORITY-CHECK가 최종적으로 데이터를 필터링합니다.
비유하자면 ICF는 건물 정문, Gateway 등록은 로비 안내데스크, S_SERVICE는 엘리베이터 카드, CDS DCL/AUTHORITY-CHECK는 개별 사무실 도어락에 해당합니다. 정문이 열려 있고 로비를 통과해도 사무실 도어락이 없으면 아무나 들어가는 상황이 됩니다.
실전 예제 1단계: 기본 OData 엔티티 권한 체크
SalesOrder 조회 서비스에 최소한의 권한 체크를 넣는 예제입니다. SEGW 방식 Data Provider Class(DPC_EXT)에서 재정의합니다.
METHOD salesorderset_get_entityset.
DATA: lv_sales_org TYPE vkorg,
lt_orders TYPE TABLE OF zsales_order_dto.
READ TABLE it_filter_select_options WITH KEY property = 'SalesOrg'
ASSIGNING FIELD-SYMBOL(<fs_filter>).
IF sy-subrc = 0 AND <fs_filter>-select_options IS NOT INITIAL.
lv_sales_org = <fs_filter>-select_options[ 1 ]-low.
ENDIF.
AUTHORITY-CHECK OBJECT 'V_VBAK_VKO'
ID 'VKORG' FIELD lv_sales_org
ID 'ACTVT' FIELD '03'.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid = /iwbep/cx_mgw_busi_exception=>business_error
message = |판매 조직 { lv_sales_org }에 대한 조회 권한이 없습니다.|.
ENDIF.
SELECT vbeln, vkorg, kunnr, netwr, waerk
FROM vbak
WHERE vkorg = @lv_sales_org
INTO CORRESPONDING FIELDS OF TABLE @lt_orders
UP TO 200 ROWS.
et_entityset = lt_orders.
ENDMETHOD.
실전 예제 2단계: CDS DCL과 로깅 결합
실무에서는 엔티티셋마다 AUTHORITY-CHECK를 반복 작성하는 대신, CDS Access Control(DCL)에 선언적으로 규칙을 넣어 재사용성을 높입니다.
@EndUserText.label: 'DCL for Sales Order Access'
@MappingRole: true
define role ZSD_SALES_ORDER_ACCESS {
grant select on ZC_SALES_ORDER_HEADER
where (SalesOrg) = aspect pfcg_auth( V_VBAK_VKO, VKORG, ACTVT = '03' )
and (DistributionChannel) = aspect pfcg_auth( V_VBAK_VKO, VTWEG );
}
DCL은 조용히 필터링하기 때문에 Application Log(SLG1)로 흔적을 남겨두면 헬프데스크 대응 시간이 줄어듭니다.
METHOD log_authorization_gap.
DATA(lo_log) = cl_bali_log=>create_with_header(
header = cl_bali_header_setter=>create(
object = 'ZFIORI'
subobject = 'AUTH_TRACE'
external_id = |SO_AUTH_{ sy-uname }_{ sy-datum }| ) ).
lo_log->add_item( cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_warning
text = |사용자 { sy-uname } 판매조직 { iv_vkorg } 필터링됨| ) ).
cl_bali_log_db=>get_instance( )->save_log(
log = lo_log
assign_to_current_appl_job = abap_false ).
ENDMETHOD.
실전 예제 3단계: 프로덕션급 RAP 권한 설계
RAP에서는 Behavior Definition에 권한을 선언하고, Behavior Implementation에서 세부 로직을 처리합니다.
managed implementation in class zbp_r_salesorder_hdr unique;
strict ( 2 );
define behavior for ZR_SALES_ORDER_HEADER alias SalesOrder
persistent table zsales_order
lock master
authorization master ( instance )
etag master LastChangedAt
{
field ( readonly ) SalesOrderId, CreatedBy, CreatedAt;
field ( mandatory ) SalesOrg, SoldToParty;
create ( authorization : global );
update ( authorization : instance );
delete ( authorization : instance );
action ( authorization : instance ) Release result [1] $self;
}
METHOD get_instance_authorizations.
READ ENTITIES OF zr_sales_order_header IN LOCAL MODE
ENTITY SalesOrder
FIELDS ( SalesOrg SoldToParty )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
LOOP AT lt_orders INTO DATA(ls_order).
DATA(ls_result) = VALUE #(
%tky = ls_order-%tky
%update = if_abap_behv=>auth-unauthorized
%delete = if_abap_behv=>auth-unauthorized ).
AUTHORITY-CHECK OBJECT 'V_VBAK_VKO'
ID 'VKORG' FIELD ls_order-SalesOrg
ID 'ACTVT' FIELD '02'.
IF sy-subrc = 0.
ls_result-%update = if_abap_behv=>auth-allowed.
ENDIF.
AUTHORITY-CHECK OBJECT 'V_VBAK_VKO'
ID 'VKORG' FIELD ls_order-SalesOrg
ID 'ACTVT' FIELD '06'.
IF sy-subrc = 0.
ls_result-%delete = if_abap_behv=>auth-allowed.
ENDIF.
APPEND ls_result TO result.
ENDLOOP.
ENDMETHOD.
이 패턴의 성능 포인트는 READ ENTITIES ... IN LOCAL MODE로 한 번에 데이터를 가져와 LOOP 내부에서 SELECT를 반복하지 않는 것입니다.
흔한 실수와 트러블슈팅 FAQ
Q1. 모든 데이터가 다 보입니다. 무엇이 잘못됐나요?
CDS DCL이 없거나 @AccessControl.authorizationCheck: #NOT_REQUIRED로 설정된 경우입니다. DCL Role을 생성하고 #CHECK로 변경하세요.
Q2. SU53에는 오류가 없는데 OData 호출이 403을 반환합니다.
ICF 레벨이나 Gateway S_SERVICE에서 막힌 경우 SU53에 잡히지 않습니다. /IWFND/ERROR_LOG와 /IWBEP/ERROR_LOG를 확인하고 ST01 트레이스를 활성화하세요.
Q3. DCL이 동작하지 않습니다.
(1) DCL Role 활성화 여부, (2) @AccessControl.authorizationCheck: #CHECK 설정 여부, (3) PFCG 역할 Authorization Object 값 유지 여부를 순서대로 점검하세요.
Q4. DCL 적용 후 성능이 느려졌습니다.
ST05 SQL 트레이스로 실행 계획을 확인하고 VKORG 컬럼에 세컨더리 인덱스를 추가하거나 @AbapCatalog.dbHints를 활용하세요.
확장 학습 방향
4계층 파이프라인을 이해했다면 다음 주제로 확장해볼 만합니다. SAP BTP에서의 XSUAA 스코프 매핑, SAP Cloud IAG를 활용한 SoD 룰 정의, S/4HANA Cloud의 Business Role Template 상속 구조가 대표적입니다. RAP에서는 Draft-Enabled 시나리오의 권한 처리와 EML 기반 대량 처리 시 권한 캐싱 전략도 실무에서 자주 부딪히는 문제입니다.
댓글 0
아직 댓글이 없습니다.