RAP 권한 모델의 두 축 — Global과 Instance
RAP(RESTful Application Programming Model)에서 권한 체크는 두 단계로 분리됩니다. Global Authorization은 사용자가 해당 BO의 특정 오퍼레이션을 "원천적으로" 수행할 수 있는지 결정합니다. 반면 Instance Authorization은 "이 사용자가 이 특정 행(예: 판매조직 1010의 주문 4500000123)을 수정할 권한이 있는가?"를 묻습니다.
글로벌 권한만 구현하고 인스턴스 권한을 빠뜨리면 권한이 없는 사용자가 다른 판매조직의 주문 데이터를 변경할 수 있는 심각한 보안 사고로 이어집니다.
RAP 프레임워크는 OData 요청을 받으면 글로벌 권한을 먼저 체크하고, 통과하면 키 셋을 모아 인스턴스 권한 핸들러를 호출합니다. 인스턴스 핸들러는 키별로 허용/거부 비트맵을 채워 돌려주고, 프레임워크가 거부된 행을 처리합니다.
BDEF에서의 authorization 선언
managed implementation in class zbp_i_salesorder unique;
strict ( 2 );
with draft;
define behavior for ZI_SalesOrder alias SalesOrder
persistent table zsalesorder
draft table zsalesorder_d
lock master total etag LastChangedAt
authorization master ( instance, global ) " 두 가지 모두 선언
etag master LastChangedAt
{
create;
update;
delete;
field ( readonly ) SalesOrderID, CreatedBy, CreatedAt;
field ( mandatory ) SalesOrg, SoldToParty;
association _Items { create; with draft; }
}
define behavior for ZI_SalesOrderItem alias Item
persistent table zsalesoitem
lock dependent by _SalesOrder
authorization dependent by _SalesOrder " 부모 권한 상속
etag master LastChangedAt
{
update;
delete;
}
authorization master ( instance, global )은 글로벌과 인스턴스 두 가지 권한 핸들러를 모두 구현하겠다는 선언입니다. ADT Quick Fix로 get_instance_authorizations와 get_global_authorizations 메서드 골격이 자동 생성됩니다.
실전 예제 1단계: get_instance_authorizations 기본 구현
METHOD get_instance_authorizations.
" 키에 해당하는 SalesOrg 값 조회
READ ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
FIELDS ( SalesOrg )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders)
FAILED failed.
" 각 인스턴스별 권한 체크
LOOP AT lt_orders INTO DATA(ls_order).
AUTHORITY-CHECK OBJECT 'Z_SO_VKORG'
ID 'VKORG' FIELD ls_order-SalesOrg
ID 'ACTVT' FIELD '02'.
DATA(lv_update) = COND #(
WHEN sy-subrc = 0
THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
AUTHORITY-CHECK OBJECT 'Z_SO_VKORG'
ID 'VKORG' FIELD ls_order-SalesOrg
ID 'ACTVT' FIELD '06'.
DATA(lv_delete) = COND #(
WHEN sy-subrc = 0
THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
APPEND VALUE #(
%tky = ls_order-%tky
%update = lv_update
%delete = lv_delete
) TO result.
ENDLOOP.
ENDMETHOD.
READ ENTITIES ... IN LOCAL MODE는 권한 체크를 우회하므로 권한 핸들러 내부에서 무한 재귀를 막아줍니다.
실전 예제 2단계: 액션 권한과 비즈니스 규칙 결합
METHOD get_instance_authorizations.
READ ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
FIELDS ( SalesOrg OverallStatus )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
LOOP AT lt_orders ASSIGNING FIELD-SYMBOL().
DATA(ls_result) = VALUE result_row( %tky = -%tky ).
" 업데이트 권한
IF requested_authorizations-%update = if_abap_behv=>mk-on.
AUTHORITY-CHECK OBJECT 'Z_SO_VKORG'
ID 'VKORG' FIELD -SalesOrg
ID 'ACTVT' FIELD '02'.
ls_result-%update = COND #(
WHEN sy-subrc = 0
THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
ENDIF.
" 삭제 권한 — 이미 release된 주문은 삭제 금지
IF requested_authorizations-%delete = if_abap_behv=>mk-on.
IF -OverallStatus = 'R'.
ls_result-%delete = if_abap_behv=>auth-unauthorized.
ELSE.
AUTHORITY-CHECK OBJECT 'Z_SO_VKORG'
ID 'VKORG' FIELD -SalesOrg
ID 'ACTVT' FIELD '06'.
ls_result-%delete = COND #(
WHEN sy-subrc = 0
THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
ENDIF.
ENDIF.
APPEND ls_result TO result.
ENDLOOP.
ENDMETHOD.
requested_authorizations의 control 비트를 검사하여 실제 요청된 권한만 평가하는 것이 성능상 중요합니다. 모든 권한을 매번 평가하면 대량 조회 시 AUTHORITY-CHECK 호출이 폭증합니다.
실전 예제 3단계: get_global_authorizations
METHOD get_global_authorizations.
IF requested_authorizations-%create = if_abap_behv=>mk-on.
AUTHORITY-CHECK OBJECT 'Z_SO_VKORG'
ID 'VKORG' DUMMY
ID 'ACTVT' FIELD '01'.
result-%create = COND #(
WHEN sy-subrc = 0
THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
ENDIF.
ENDMETHOD.
VKORG에 DUMMY를 넣은 것은 "어떤 VKORG든 하나라도 생성 권한이 있는가"를 묻는 것입니다. 실제 입력된 VKORG에 대한 정밀 체크는 precheck에서 수행합니다.
Features 메서드와 권한 연동
UI 일관성을 위해 get_features와 get_instance_authorizations가 동일한 권한 로직을 호출해야 합니다. 두 메서드가 다른 결과를 반환하면 버튼은 활성화되는데 실제 액션에서 권한 오류가 발생합니다. 공통 헬퍼 클래스로 권한 로직을 추출해 양쪽에서 재사용하는 것이 권장 패턴입니다.
RAP 권한 vs CDS DCL — 읽기 필터링 오해
get_instance_authorizations는 "쓰기 권한"을 결정할 뿐 "읽기 필터링"은 하지 않습니다. List Report에서 거부된 행을 숨기려면 CDS Access Control(DCL, define role)로 별도 구현해야 합니다. RAP 권한과 DCL을 혼동하는 것이 가장 흔한 오해입니다.
운영 환경 권한 테스트 방법
- SU53: 마지막 실패한 권한 체크 조회 — 권한 오브젝트/필드 확인
- SUIM: 사용자 권한 역추적
- ABAP Unit + 테스트 더블: AUTHORITY-CHECK를 인터페이스로 추상화 후 Mock으로 교체
- CDS Test Double Framework: 데이터 시드 없이 권한 시나리오 검증
권한 설계 체크리스트
- BDEF: authorization master ( instance, global ) 선언 확인
- 자식 엔티티: authorization dependent by _Parent 선언
- get_instance_authorizations: READ ENTITIES IN LOCAL MODE 사용
- requested_authorizations 비트 검사로 불필요한 체크 제거
- VKORG-ACTVT 단위 캐시 적용 (대량 처리 시)
- 읽기 필터링은 CDS DCL로 별도 구현
- get_features와 권한 로직 일관성 유지
흔한 실수와 트러블슈팅
- List Report에 거부된 행이 그대로 노출됨: 읽기 필터링은 CDS DCL로 별도 구현 필요. 인스턴스 권한은 쓰기 제어만 담당.
- Features 버튼 활성인데 액션 권한 오류: get_features와 get_instance_authorizations 결과 불일치. 공통 헬퍼로 로직 통일 필요.
- 대량 처리 시 응답 느림: 키별 SELECT 반복, 캐시 없는 AUTHORITY-CHECK 반복. READ ENTITIES 한 번 + VKORG-ACTVT 캐시로 개선.
- 인스턴스 권한 무한 재귀: READ ENTITIES에 IN LOCAL MODE 누락.
댓글 0
아직 댓글이 없습니다.
💬 댓글 작성, 좋아요, 북마크는 UI5 모드에서 사용할 수 있습니다.
UI5 모드에서 사용하기