Blog SAPienteSAPiente
CDS Views

CDS Access Control (DCL) na prática: o guia completo de controle de acesso por linha no ABAP

SAPiente9 de jun. de 2026· 5 min read

Quem decide quais linhas o usuário enxerga?

No ABAP clássico, filtrar dados por autorização significava espalhar AUTHORITY-CHECK e cláusulas WHERE manuais por todo lugar — fácil de esquecer, difícil de manter. O CDS Access Control resolve isso de forma declarativa: você descreve a regra uma vez, em DCL (Data Control Language), e o kernel a aplica implicitamente em toda leitura da entidade.

A ideia central: uma CDS role não é atribuída a usuários — ela é avaliada para cada usuário a cada acesso, e o motor injeta um WHERE derivado das condições que você definiu. O resultado vale uniformemente em OData, EML, ABAP SQL, analytics — qualquer consumidor da CDS.

Este é um guia de referência completo do DCL: a annotation que liga a checagem, os tipos de condição (PFCG, user, literal), herança entre views, COMBINATION MODE, REDEFINITION e o bypass via PRIVILEGED ACCESS — com exemplos e as armadilhas que mais derrubam gente.

O essencial em 4 linhas

  • DCL filtra linhas na leitura, declarativamente. A CDS role é avaliada para todo usuário, não atribuída a ninguém.

  • A checagem só vale no acesso direto à entidade que carrega a DCL — não se propaga para quem faz SELECT FROM ela.

  • PFCG condition integra objetos de autorização clássicos; user condition filtra "meus registros"; literal compara com valores fixos/sessão.

  • DCL cobre leitura; modificação (create/update/delete) fica na Behavior Definition do RAP.

O que é CDS Access Control e quando aplicá-lo?

CDS Access Control restringe implicitamente as linhas retornadas por uma CDS entity quando ela é acessada via ABAP SQL. A checagem acontece na camada do modelo de dados, complementando — e em muitos cenários substituindo — os clássicos AUTHORITY-CHECK (SAP Help — ABAP CDS Access Control). Suportam DCL: CDS Views, View Entities, Hierarchies, Table Functions e Transactional Queries.

A regra que pega todo mundo: a checagem é aplicada somente no acesso direto à entidade que possui a DCL. Segundo a documentação, "quando uma CDS entity usada como data source em outras entidades é acessada indiretamente, nenhum controle de acesso implícito é aplicado". Ou seja: uma view #NOT_ALLOWED consumida por outra #CHECK bypassa a proteção, porque o motor só checa a entidade consultada diretamente.

Como a annotation @AccessControl.authorizationCheck controla a checagem?

A annotation @AccessControl.authorizationCheck define o comportamento da entidade frente ao controle de acesso. O valor padrão é #CHECK. Há um detalhe que confunde muita gente: a diferença entre #CHECK e #NOT_REQUIRED é só o aviso de ativação, não "ligado vs. desligado".

Valor

O que faz

Quando usar

#CHECK (padrão)

Aplica a DCL se existir; emite aviso na ativação se não houver role.

Entidades expostas a usuários finais.

#NOT_REQUIRED

Não desliga o controle — só suprime o aviso. Se houver role, ela é aplicada.

Views auxiliares onde a DCL é opcional.

#MANDATORY

Exige que exista uma DCL; do contrário, erro.

Entidades sensíveis (HR, financeiro).

#NOT_ALLOWED

Desliga de fato o controle; roles são ignoradas.

Views técnicas privadas, nunca expostas.

#PRIVILEGED_ONLY

Só pode ser lida com WITH PRIVILEGED ACCESS no ABAP SQL.

Entidades de acesso exclusivamente privilegiado.

@AccessControl.authorizationCheck: #CHECK
define view entity ZI_SalesOrder
  as select from vbak
{
  key vbeln as SalesOrder,
      auart as SalesOrderType,
      vkorg as SalesOrganization,
      netwr as NetAmount
}

Mito corrigido: #NOT_REQUIRED não abre vazamento de dados por si só — ele só silencia o aviso de "role ausente". O risco real é indireto: ao remover o lembrete, você pode esquecer de criar a role, e sem role não há filtro. Quem desliga de fato o controle é #NOT_ALLOWED.

Como é a estrutura de uma DEFINE ROLE?

Uma define role é o container das regras de acesso. Ela pode conter várias grant select on para entidades distintas, e a mesma entidade pode aparecer em várias regras ou várias roles — combinadas por OR por padrão. Lembre: a role é avaliada para todo usuário, não atribuída a ninguém.

Existem dois tipos de regra. A full access rule (sem WHERE) concede acesso irrestrito — use só em dados públicos, como tabelas de customizing (códigos de país, moeda):

define role ZI_CONFIG_TABLE_FULL {
  grant select on ZI_ConfigTable;     // acesso pleno a todos
}

A conditional access rule (com WHERE) é a forma comum: restringe linhas por condições, que podem combinar literal, PFCG e user com AND/OR:

define role ZI_SALES_ORDER {
  grant select on ZI_SalesOrder
    where ( SalesOrganization = '1010' OR CurrencyCode = 'EUR' )
      and CreatedOn between '20240101' and '20241231';
}

Os operadores de uma literal condition incluem =, <>, <, >, [NOT] BETWEEN, [NOT] LIKE e IS [NOT] NULL. Você também compara com variáveis de sessão, útil para multi-cliente:

define role ZI_CLIENT_DATA {
  grant select on ZI_SalesOrder
    where Client = $session.client;
}

Como filtrar por autorização PFCG (aspect pfcg_auth)?

A PFCG condition é a integração nativa com os objetos de autorização clássicos (criados em SU21). É o padrão para qualquer dado de negócio em S/4HANA com governança de roles já existente. A regra de ouro da sintaxe: a quantidade de elementos CDS à esquerda deve coincidir com a de campos mapeados à direita, na mesma ordem — o mapeamento é posicional (SAP Help — pfcg_condition).

@MappingRole: true
@EndUserText.label: 'DCL para ZI_SalesOrder'
define role ZI_SALES_ORDER {
  grant select on ZI_SalesOrder
    where
      ( SalesOrderType ) =
        aspect pfcg_auth( V_VBAK_AAT, AUART, ACTVT = '03' )
      and
      ( OrganizationDivision, SalesOrganization, DistributionChannel ) =
        aspect pfcg_auth( V_VBAK_VKO, SPART, VKORG, VTWEG, ACTVT = '03' );
}

Só voltam as linhas para as quais o usuário tem autorização em ambos os objetos. Há variações úteis:

  • Gate booleano (parênteses vazios à esquerda): não filtra linhas — é tudo ou nada. Se o usuário tiver ao menos uma autorização no objeto, a condição é verdadeira.

  • Mesmo campo dos dois lados: usa os valores da autorização como filtro direto.

// Gate: acesso pleno ou nenhum, sem filtrar linhas
where ( ) = aspect pfcg_auth( S_DEVELOP, ACTVT = '03' );

// Mesmo campo: filtra pelos valores autorizados
where ( CarrierId ) = aspect pfcg_auth( S_CARRID, CARRID, CARRID = 'LH' );

Correção importante sobre o operador ?=: muita fonte (e muito tutorial) afirma que ?= significa "se o usuário não tiver autorização nenhuma, libera acesso pleno". Isso está errado. Segundo a documentação oficial, ?= funciona como o =, mas a condição também é satisfeita quando os elementos CDS à esquerda têm valor NULL ou inicial. É um operador de tolerância a NULL/inicial — não um override de "autorização ausente".

Como filtrar pelos registros do próprio usuário (aspect user)?

A user condition compara um elemento da CDS com o usuário logado — o equivalente de comparar com sy-uname, mas avaliado pelo motor da DCL. É a forma certa para "meus pedidos", "minhas tarefas", "meus tickets" (SAP Help — user condition).

define role ZI_MY_ORDERS {
  grant select on ZI_SalesOrder
    where CreatedBy = aspect user;
}

Os operadores válidos são =, <> e ?=. E sim, o mesmo cuidado do ?= vale aqui: ele tolera NULL/inicial, não "libera quem não tem alias". Você pode combinar com NULL para tratar registros "sem dono" como públicos:

define role ZI_OWN_DOCS {
  grant select on ZI_DocMode
    where ( UserName = aspect user
         or UserName is initial
         or UserName is null );
}

Nuance de sintaxe: aspect user é o equivalente em DCL de $session.user, mas não é a mesma coisa: $session.user é um recurso de DDL e variáveis de sessão não podem ser usadas dentro da DCL. Dentro de uma role, use aspect user.

Como reaproveitar regras com herança (INHERITING CONDITIONS FROM)?

A inheritance condition reutiliza as condições já definidas em outra DCL, evitando duplicação — o pilar da estratégia VDM (Virtual Data Model), onde a Consumption View (ZC_*) herda da Interface View (ZI_*) (SAP Help — inherit_condition).

define role ZC_SALES_ORDER {
  grant select on ZC_SalesOrder
    where inheriting conditions from entity ZI_SalesOrder;
}

Você pode até substituir valores de campos PFCG na herança com REPLACING — por exemplo, transformar autorização de exibição (03) em alteração (02) na view derivada:

define role ZC_SALES_ORDER_CHG {
  grant select on ZC_SalesOrderChg
    where inheriting conditions from entity ZI_SalesOrder
      replacing { pfcg_filter field ACTVT value '03' with '02' };
}

Correção sobre o DEFAULT: ao contrário do que circula por aí, nem DEFAULT TRUE nem DEFAULT FALSE é "o padrão". Omitir a cláusula DEFAULT gera erro de sintaxe caso a entidade-fonte não tenha uma role. Defina explicitamente: DEFAULT TRUE = acesso pleno se o pai não tiver DCL; DEFAULT FALSE = bloqueia tudo (mais seguro).

Como combinar várias regras (COMBINATION MODE OR/AND)?

Quando há várias regras para a mesma entidade, o COMBINATION MODE define como elas se combinam. O padrão é OR (regras implicitamente unidas por "ou"), que amplia o acesso; o AND estreita (SAP Help — conditional_rule).

// OR (padrão) — vê linhas se tem PFCG OU é o criador
define role ZI_ORDER_PERMISSIVE {
  grant select on ZI_SalesOrder combination mode or
    where ( SalesOrderType ) = aspect pfcg_auth( V_VBAK_AAT, AUART );
  grant select on ZI_SalesOrder combination mode or
    where CreatedBy = aspect user;
}

A fórmula resultante quando há regras dos dois modos é:

( cond_or_1 OR cond_or_2 OR ... ) AND cond_and_1 AND cond_and_2 AND ...

Atenção: uma full access rule anula a construção acima. Se existir uma regra de acesso pleno para a entidade, o resultado é acesso pleno — mesmo havendo regras com COMBINATION MODE AND. Não misture as duas coisas sem perceber.

Como substituir a DCL entregue pela SAP (REDEFINITION)?

O REDEFINITION permite ao cliente/parceiro substituir toda a DCL entregue pela SAP para uma entidade, sem modificação. É poderoso e arriscado: após a ativação, só a sua regra vale, e melhorias futuras da SAP naquela DCL deixam de ser aplicadas. Ele só pode ser usado uma vez por entidade (mais que isso gera erro de ativação) e apenas em sistemas de cliente.

// Substituição total
define role ZC_REDEFINE_SALES {
  grant select on I_SalesDocument
    redefinition
    where SalesOrganization = '1710';
}

Para não perder as condições originais, traga-as de volta com INHERITING CONDITIONS FROM SUPER e acrescente exceções:

define role ZC_REDEFINE_KEEP {
  grant select on I_SalesDocument
    redefinition
    where inheriting conditions from super
       or SalesOrganization = '9999';
}

Como restringir por associações (ALL, EXISTS e BYPASS WHEN)?

Para condições sobre path expressions (associações), o DCL oferece quantificadores. ALL exige que todos os registros associados atendam; EXISTS exige pelo menos um. São recursos mais recentes — disponíveis a partir do release 7.55 (SAP Help — literal condition).

// Acesso ao projeto só se TODAS as tarefas estão concluídas
where all _ProjectTasks.Status = 'COMPLETED';

// Pelo menos uma tarefa concluída
where exists _ProjectTasks.Status = 'COMPLETED';

O BYPASS WHEN exclui do filtro os registros associados com valor nulo/inicial — sem ele, tarefas com status NULL quebrariam a cláusula ALL:

where all ( _ProjectTasks.Status = 'COMPLETED' bypass when is null );

Cuidado com performance: ALL/EXISTS sobre associações podem gerar subqueries pesadas. Teste antes de usar em entidades de alto volume — e evite-os em entidades simples sem associação, onde só aumentam a complexidade.

PRIVILEGED ACCESS, roles SWITCHABLE e o modo de emergência

Quando um job técnico precisa de visão consolidada, o WITH PRIVILEGED ACCESS no ABAP SQL ignora a DCL daquela leitura. Use só em código bem auditado — nunca em handler exposto ao usuário final. É também o caminho obrigatório para ler entidades marcadas como #PRIVILEGED_ONLY.

SELECT * FROM zi_salesorder WITH PRIVILEGED ACCESS
  INTO TABLE @DATA(lt_orders).

Já o SWITCHABLE liga a role ao Switch Framework, útil para funcionalidades opcionais. Atenção às restrições documentadas: numa role switchable o COMBINATION MODE é obrigatório, e REDEFINITION e herança não são permitidos.

@MappingRole: true
define role switchable ZI_OPTIONAL_AUTH {
  grant select on ZI_SalesOrder combination mode or
    where ( SalesOrganization ) = aspect pfcg_auth( V_VBAK_VKO, VKORG );
}

Dois fatos úteis: no modo de emergência (usuário SAP*), o CDS access control é desativado — e isso afeta condições PFCG, literais e de usuário, todas. E o Data Preview do ADT respeita a DCL: para entidades #PRIVILEGED_ONLY, você precisa adicionar WITH PRIVILEGED ACCESS para conseguir visualizar.

Sobre o @MappingRole: para que serve mesmo?

Aqui há outra confusão comum. A annotation @MappingRole: true não é uma exigência específica do aspect pfcg_auth. Seu papel real: marcar a role como uma mapping role, fazendo com que ela seja atribuída/aplicada a todos os usuários, independentemente de cliente. Se você usá-la, o valor deve ser true.

Na prática, é boa prática incluí-la nas suas DCLs — mas pelo motivo certo (aplicar a role a todos), não porque "o PFCG exige".

DCL e RAP: leitura vs. modificação

O DCL protege apenas a leitura. Para create, update, delete e actions, a proteção fica na Behavior Definition do RAP, via Global e Instance Authorization. Os dois são complementares: DCL filtra o que o usuário lê; a Behavior Authorization controla o que ele pode alterar.

define behavior for ZI_SalesOrder alias SalesOrder
persistent table zsalesorder
lock master
authorization master ( instance )
{
  create;
  update;
  delete;
  action approveOrder authorization:instance;
  action cancelOrder  authorization:global;
}

Quer o quadro completo da modificação? O DCL é só a camada de leitura. Para entender Global vs. Instance Authorization — e quando usar cada uma — veja o guia Os 3 tipos de autorização no SAP RAP: DCL, Global e Instance.

Boas práticas e armadilhas

Algumas práticas mantêm o DCL seguro e sustentável. A mais importante: defina a DCL ao mesmo tempo que a CDS, não como passo posterior — e concentre a regra "fonte" na camada Interface, deixando a Consumption herdar via INHERITING CONDITIONS FROM ENTITY.

  • Declare @AccessControl.authorizationCheck explicitamente em toda entidade exposta.

  • Use #MANDATORY em entidades sensíveis (HR, financeiro).

  • Em ABAP Cloud, use só objetos de autorização released (contrato C1).

  • Combine DCL (leitura) + RAP authorization (modificação) para um BO completo.

  • Logue cada WITH PRIVILEGED ACCESS para auditoria e bloqueie SAP* em produção.

Antipadrão

Risco

#NOT_ALLOWED em view consumida diretamente

Dados sensíveis expostos

WITH PRIVILEGED ACCESS para "destravar" testes

Esquecimento em produção

Full access rule "temporária"

Permanece e libera dados em prod

REDEFINITION sem INHERITING FROM SUPER

Perde melhorias SAP em upgrades

DCL na Consumption sem herdar da Interface

Regras duplicadas que divergem

Misturar COMBINATION MODE AND com full access rule

Full access vence; o AND é ignorado

Uma observação honesta sobre limites: ao contrário do que alguns blogs afirmam, não existe um "máximo de 4 níveis de AND" oficial na documentação. Estruture as condições pela clareza, não por um limite inventado.

Perguntas frequentes

O DCL substitui o AUTHORITY-CHECK clássico?

Para filtrar linhas na leitura, sim — o DCL é o mecanismo moderno e declarativo. Mas para start authorization (permitir entrar na app) você ainda usa AUTHORITY-CHECK no início do programa, e para modificações usa a autorização do RAP. DCL não cobre tudo; cobre leitura.

Por que minha view com DCL ainda mostra tudo quando consumida por outra?

Porque o controle de acesso só é aplicado no acesso direto à entidade que tem a DCL. Quando outra view faz SELECT FROM a sua, a DCL interna não dispara. A proteção precisa estar na entidade efetivamente consultada — por isso a Consumption View deve herdar via INHERITING CONDITIONS FROM ENTITY.

O que o operador ?= realmente faz?

Ele funciona como o =, mas a condição também é satisfeita quando os elementos CDS à esquerda têm valor NULL ou inicial. É tolerância a nulos — não "libera acesso pleno para quem não tem autorização", como muitas fontes afirmam erroneamente. Vale tanto para PFCG quanto para user condition.

Preciso de @MappingRole: true sempre?

Não é uma exigência do pfcg_auth, como muito material diz. Ele marca a role como mapping role, aplicada a todos os usuários independentemente de cliente; se presente, o valor deve ser true. É boa prática incluí-lo — mas pelo motivo correto, não por causa do PFCG.

Como desligo a DCL para um job técnico?

Use WITH PRIVILEGED ACCESS no SELECT, em código auditado. Em RAP, o equivalente é a leitura IN LOCAL MODE, que também pula o controle de acesso. Nunca deixe esses bypasses em código exposto ao usuário final — eles furam todo o modelo de segurança.

Conclusão

O CDS Access Control transforma controle de acesso por linha de um emaranhado de AUTHORITY-CHECK num modelo declarativo, central e reaproveitável. Escolha a condição certa para cada caso — PFCG para roles existentes, user para "meus registros", literal para valores fixos —, herde entre camadas com INHERITING CONDITIONS e reserve REDEFINITION e PRIVILEGED ACCESS para os casos específicos que os justificam.

E lembre dos dois enganos mais comuns que este guia corrige: o ?= é tolerância a NULL (não override de autorização), e a checagem só vale no acesso direto à entidade. Combine DCL na leitura com a autorização do RAP na modificação, e o seu Business Object fica protegido de ponta a ponta.

Referências oficiais

TagsClean CoreDesenvolvedorHANA
Avalie este conteúdo
para avaliar
SAPiente
@sapiente

Blog sobre SAP, ABAP, BTP, Fiori e tudo que envolve o ecossistema SAP.

Ver perfil →
FacebookInstagramYouTubeTwitter

Comentários 0

Entre na conversa

Faça login para deixar seu comentário neste artigo.

Ainda sem comentários

Seja o primeiro a comentar este artigo.