Saltar para o conteúdo principal
Versão: Próximo

Roles and Privileges

A arquitetura de segurança ORDA controla o acesso aos recursos do projeto para sessões web e REST. Ela permite conceder permissões específicas em recursos como o datastore, dataclasses, atributos e funções.

Visão Geral​

O modelo de segurança combina privilégios, ações (como read e create) e recursos.

Atribua privilégios a uma sessão usando Session.setPrivileges().

Cada requisição é verificada em relação às permissões definidas no arquivo roles.json do projeto. Uma ação não autorizada gera um erro de privilégio. Atributos sem permissão de leitura são omitidos da resposta.

schema

info

Permissões controlam o acesso a objetos ou funções de armazenamento de dados. Se você deseja filtrar os dados lidos de acordo com alguns critérios, você pode considerar restringir as seleções de entidades que pode ser mais apropriado neste caso.

Escopo​

As permissões se aplicam a sessões web e REST: requisições REST, incluindo páginas Qodly, e código 4D executado em um processo web. Isso inclui funções expostas, HTTP request handlers, o método de banco de dados On Web Connection, e qualquer código chamado por eles. Por exemplo, uma chamada de função permitida ainda falha se a função ler uma dataclass para a qual a sessão não tem permissão de leitura.

Exception

A permissão execute de um singleton compartilhado ou função singleton é verificada apenas quando a função é chamada via REST. Quando código 4D rodando em uma sessão web chama diretamente (cs.MySingleton.me.myFunction()), nenhuma permissão é verificada, ao contrário de funções de dataclass, entity, entity selection e datastore, que são verificadas em ambos os casos.

Permissões nunca se aplicam a código de sessão desktop (standalone, client/server, stored procedures) ou tool4d.

Ferramentas MCP​

As mesmas permissões se aplicam às sessões do servidor MCP, sem nada específico para configurar:

  • Uma ferramenta personalizada (exposed MCP Function) requer permissão execute em sua função, e se beneficia da permissão promote.
  • As ferramentas CRUD integradas requerem permissão read, create, update ou drop na dataclass, e as permissões de atributo se aplicam. Cada atributo de um caminho usado em filtro, ordenação ou projeção requer permissão read.
  • As ferramentas CRUD só são listadas se a sessão tiver pelo menos uma permissão de dados em uma dataclass, e a ferramenta describeModel só descreve as dataclasses nas quais a sessão tem permissão de dados, com seus atributos legíveis ou graváveis.
  • Uma ferramenta, dataclass ou atributo que a sessão não pode acessar é relatado como se não existisse.

Exemplo​

Clientes MCP autenticados com o privilégio "salesReader" podem ler as dataclasses Customer e Order com as ferramentas CRUD, e chamar as ferramentas publicadas pelo singleton OrderManager (por exemplo, OrderManager-getYearTotal):

{
"privileges": [{"privilege": "salesReader", "includes": []}],
"roles": [],
"permissions": {
"allowed": [
{"applyTo": "Customer", "type": "dataclass", "read": ["salesReader"]},
{"applyTo": "Order", "type": "dataclass", "read": ["salesReader"]},
{"applyTo": "OrderManager", "type": "singleton", "execute": ["salesReader"]}
]
},
"restrictedByDefault": true
}

Recursos​

O 4D verifica as permissões da sessão sempre que um recurso é acessado. Os seguintes recursos podem ter permissões específicas:

RecursoapplyTotype
Datastoredsdatastore
Função de classe Datastoreds.<function>method
Dataclass<Dataclass>dataclass
Atributo (incluindo computed e alias)<Dataclass>.<attribute>attribute
Função de dataclass, entity ou entity selection<Dataclass>.<function>method
Singleton compartilhado (todas as funções expostas)<Singleton>singleton
Função singleton<Singleton>.<function>singletonMethod

Use os valores de applyTo e type mostrados na tabela ao definir permissões no roles.json.

Atribuição de permissões a funções de classe ORDA

No roles.json, identifique uma função de classe ORDA em applyTo com esta sintaxe:

<DataclassName>.<functionName>

Por exemplo, se você quiser aplicar uma permissão à seguinte função:

// cs.CityEntity class
Class extends Entity
Function getPopulation() : Integer
...

Use este valor:

"applyTo":"City.getPopulation"

Como as permissões identificam funções por dataclass e nome da função, funções com o mesmo nome em diferentes classes ORDA (entity, entity selection, dataclass) não podem receber privilégios diferentes. Dê nomes distintos a elas. Por exemplo, nomeie as funções como dropEntity() e dropSelection() em cs.CityEntity e cs.CitySelection, respectivamente:

"permissions": {
"allowed": [
{
"applyTo": "City.dropEntity",
"type": "method",
"promote": [
"name"
]
},
{
"applyTo": "City.dropSelection",
"type": "method",
"promote": [
"name"
]
}
]
}
}

Permissões​

Uma permissão permite uma ação em um recurso; por exemplo, executar ds.myTable.myFunction(). Permissões são definidas em roles.json e concedidas a um ou mais privilégios.

Se nenhuma permissão for definida para um recurso, o acesso depende do modo de restrição do projeto.

Ações de permissão​

As ações disponíveis dependem do recurso:

AçãoDatastoreDataclassAtributoFunção
createCriar entidades em qualquer dataclassCriar entidades nesta dataclassCriar uma entidade com valor diferente do padrão para este atributo (ignorado para atributos alias)n/a
readLer atributos em qualquer dataclassLer atributos nesta dataclassLer o conteúdo deste atributon/a
updateAtualizar atributos em qualquer dataclassAtualizar atributos nesta dataclassAtualizar o conteúdo deste atributo (ignorado para atributos alias)n/a
drop ("Delete" no Qodly Studio)Excluir dados em qualquer dataclassExcluir dados nesta dataclassExcluir um valor não nulo para este atributo (exceto para alias e atributos computados)n/a
executeExecutar qualquer função no projeto (datastore, dataclass, entity selection, entity ou singleton)Executar qualquer função na dataclass; funções de dataclass, entity e entity selection são tratadas como funções de dataclassn/aExecutar esta função
promoten/an/an/aAdiciona temporariamente um privilégio durante a chamada da função. Apenas o processo que executa a função recebe o privilégio, não toda a sessão. Use promote() e demote() para definir ou remover esta ação dinamicamente em um processo web.

Regras de permissão​

  • update e drop requerem read no recurso; create não requer.
  • Uma função pode ser promoted por múltiplos privilégios. Durante a execução, ela recebe as permissões combinadas de todos esses privilégios; não há ordem de prioridade.
  • Um atributo alias pode ser lido se a sessão tiver permissão para ler o alias, mesmo que não possa ler os atributos que o alias resolve.
  • Um atributo computado pode ser acessado mesmo que seus atributos subjacentes não tenham permissões.
  • No REST modo de login forçado, usuários guest sempre podem executar authentify(), independentemente da configuração de permissões.

Permissões herdadas​

Ações de permissão são herdadas conforme as seguintes regras:

  1. Permissões descem datastore → dataclass → atributo / função, e datastore → singleton → função singleton.
  2. A resolução é por ação. Definir read em uma dataclass não altera como create, update, drop ou execute são resolvidos para ela.
  3. Dataclass substitui datastore. Uma permissão definida em uma dataclass para uma ação substitui a permissão do datastore para essa ação. Privilégios concedidos apenas no datastore perdem o acesso naquela dataclass.
  4. Função substitui dataclass. Uma permissão execute definida em uma função substitui a permissão execute da dataclass (e do datastore) para aquela função. Funções de entity e entity selection seguem a mesma regra das funções de dataclass.
  5. Singleton substitui datastore, função singleton substitui singleton.
  6. Função de datastore substitui datastore.
  7. Atributo soma ao pai. Para agir em um atributo que tem permissão própria, a sessão precisa de um privilégio concedido pela permissão do atributo e um privilégio concedido para a ação na dataclass (diretamente ou via datastore).
  8. Uma ação concedida a nenhum privilégio (por exemplo, "read": []) é "não definida", então a permissão do nível acima se aplica. Não significa "ninguém". Para negar a ação, use modo restrito sem definir aquela permissão, ou conceda a um privilégio que nenhuma sessão recebe.

Permissões apenas concedem acesso; não há negação explícita. Uma permissão de dataclass ou função pode, portanto, restringir uma permissão mais ampla do datastore ao substituí-la. Uma permissão de atributo é aditiva: concede acesso ao atributo apenas quando a sessão também tem a ação na dataclass.

Prática recomendada
  • Conceda acesso às sessões por meio de funções com Session.setPrivileges({roles: [...]}). Defina funções em torno de perfis de negócio; privilégios são blocos reutilizáveis. O Qodly Studio exibe permissões efetivas por função.
  • Se uma função administrativa precisa de acesso total, inclua todos os privilégios nela, exceto um privilégio de bloqueio, se usado. Adicione cada novo privilégio a essa função: uma permissão de dataclass pode substituir uma permissão mais ampla do datastore.
  • Revise o efeito das mudanças de privilégio em cada função. No Qodly Studio, a Revisão Detalhada de Permissões mostra o acesso efetivo de uma função; uma função sem privilégios pode ajudar a revisar o acesso apenas de guest.

Privilégios e funções​

Um privilégio concede ações sobre recursos. Uma função agrupa privilégios em um perfil de negócio que um administrador pode atribuir a uma sessão.

Por exemplo, manageInvoices pode ser um privilégio e secretary uma função que o inclui e outros privilégios. Atribua funções às sessões com Session.setPrivileges({roles: [...]}); a função concede todos os seus privilégios.

Privilégios podem receber permissão em múltiplas combinações ação-recurso, e uma ação pode ser concedida a múltiplos privilégios.

Defina privilégios e funções em roles.json, depois conceda funções às sessões com Session.setPrivileges().

Inclusão de privilégios​

Um privilégio pode incluir outros privilégios usando a propriedade includes no roles.json. A inclusão é transitiva e unidirecional: se A inclui B, e B inclui C, A recebe as permissões de B e C.

Session.getPrivileges() retorna a coleção expandida (por exemplo, A, B e C) sem ordem garantida. Declare um privilégio incluído antes do privilégio que o inclui; caso contrário, o 4D descarta a inclusão e registra um erro.

Exemplo​

Esta função de autenticação atribui a função do usuário à sessão:


exposed Function authenticate($identifier : Text; $password : Text)->$result : Text

var $user : cs.UsersEntity

Session.clearPrivileges()

$result:="Você está autenticado como Convidado"

$user:=ds.Users.query("identifier = :1"; $identifier).first()

If ($user#Null)
If (Verify password hash($password; $user.password))
Session.setPrivileges(New object("roles"; $user.role))
$result:="Você está autenticado como "+$user.role
End if
End if


Privilégio guest​

guest é embutido; declarar um privilégio chamado Guest é um erro ("privilege already defined"). Sessões sem privilégios (Session.isGuest() = True) recebem as permissões concedidas a guest.

Permissões concedidas a guest estão disponíveis para toda sessão, independentemente de seus outros privilégios. Não conceda a guest acesso que deva ser negado a outras sessões, e leve em conta suas permissões ao restringir acesso no nível da dataclass.

arquivo roles.json​

As configurações de segurança web do projeto são definidas em roles.json:

PropriedadeTipoObrigatórioDescrição
privilegesColeção de objetos de privilégioSimPrivilégios definidos. Cada objeto tem um nome privilege e pode ter uma coleção includes de nomes de privilégios.
rolesColeção de objetos de funçãoNãoFunções definidas. Cada objeto tem um nome role e uma coleção privileges de nomes de privilégios.
permissions.allowedColeção de objetos de permissãoSimPermissões atribuídas a recursos.
permissions.allowed[].applyToTextoSimNome do recurso alvo.
permissions.allowed[].typeTextoSimTipo de recurso: datastore, dataclass, attribute, method, singletonMethod ou singleton.
permissions.allowed[].readColeção de stringsNãoPrivilégios com acesso de leitura.
permissions.allowed[].createColeção de stringsNãoPrivilégios com acesso de criação.
permissions.allowed[].updateColeção de stringsNãoPrivilégios com acesso de atualização.
permissions.allowed[].dropColeção de stringsNãoPrivilégios com acesso de exclusão.
permissions.allowed[].executeColeção de stringsNãoPrivilégios com acesso de execução.
permissions.allowed[].promoteColeção de stringsNãoPrivilégios concedidos temporariamente durante a execução da função.
restrictedByDefaultBooleanoNãoSe true, o acesso a recursos sem permissões explícitas é negado.
forceLoginBooleanoNãoSe true, ativa o modo de login forçado.
Notas
  • O nome de privilégio WebAdmin é reservado para a aplicação; não o utilize para privilégios personalizados.
  • Nomes de privilégio e função não diferenciam maiúsculas de minúsculas. Nomes desconhecidos passados para .setPrivileges() são ignorados.
  • O Qodly Studio pode adicionar uma propriedade opcional id a privilégios e funções para preservar referências ao serem renomeados.
  • Múltiplas entradas com o mesmo applyTo não são mescladas: a última entrada prevalece sem erro. Defina apenas uma entrada por recurso.
  • Uma entrada de recurso que não concede nenhuma ação não tem efeito.
aviso

Quando uma entrada de permissão faz referência a um privilégio não declarado, o 4D registra um erro e ignora a entrada. Neste caso, a permissão é ignorada. Se o modo restrito por padrão não estiver habilitado, o recurso fica acessível para sessões guest.

Localização e conteúdo padrão​

Novos projetos geram o arquivo roles.json em:

<project folder>/Project/Sources/

Veja a seção Arquitetura para detalhes.

Conteúdo padrão:

/Project/Sources/roles.json

{
"privileges": [
],
"roles": [
],
"permissions": {
"allowed": [
{
"applyTo": "ds",
"type": "datastore",
"read": [],
"create": [],
"update": [],
"drop": [],
"execute": [],
"promote": []
}
]
},
"restrictedByDefault": false,
"forceLogin": false
}
Compatibidade

Em versões anteriores ao 4D 20 R6, o roles.json não era criado por padrão. No 4D 20 R6 e posteriores, ao abrir um projeto existente sem um arquivo roles.json ou configuração "forceLogin": true, o botão Ativar autenticação REST através da função ds.authentify() fica disponível na página Recursos Web da caixa de diálogo Configurações. Este botão atualiza as configurações de segurança; pode ser necessário modificar seu código. Veja este post do blog.

Qodly Studio

No Qodly Studio para 4D, o modo de login pode ser definido usando a opção Force login no painel Roles and Privileges.

Modos de restrição​

restrictedByDefault determina o acesso a um recurso quando nenhuma permissão específica é definida:

  • Modo irrestrito (restrictedByDefault: false): Recursos sem permissões definidas são acessíveis a todas as requisições.
  • Modo restrito (restrictedByDefault: true): Recursos sem permissões definidas são bloqueados. O acesso é concedido explicitamente, e as regras de herança de permissão ainda se aplicam.
Compatibidade

Estratégias de restrição​

Bloquear tudo e abrir gradualmente​

Escolha modo restrito ou um privilégio de bloqueio para fechar o acesso por padrão:

Modo restritoPrivilégio de bloqueio
Configuração"restrictedByDefault": true (Qodly Studio: Restrict Access By Default)"restrictedByDefault": false, com toda ação em ds concedida a um privilégio que nenhuma sessão recebe (por exemplo, none)
O que é fechadoTodo recurso sem permissãoTodo recurso que herda permissões do datastore
Como abrirConceda permissões no datastore, dataclasses, atributos e funçõesConceda permissões em dataclasses e funções para substituir o bloqueio
Se o 4D descartar uma entrada inválidaO recurso permanece fechadoO recurso volta ao bloqueio e permanece fechado
ImportanteConceda acesso explicitamente a recursos públicos, geralmente para guest, incluindo a função de login, a menos que force login seja usado, e HTTP request handlers chamados antes do login. Neste modo, a revisão de funções do Qodly Studio atualmente está incorreta.Nunca atribua o privilégio de bloqueio a uma função, incluindo a função administrativa.

Ambas as abordagens fecham o acesso por padrão e seguem as mesmas regras de herança e substituição. Um privilégio de bloqueio torna o bloqueio visível no editor; modo restrito não requer privilégio extra.

Abrir tudo, restringir gradualmente​

Defina modo irrestrito ("restrictedByDefault": false), conceda ao guest acesso de leitura ao ds, depois restrinja dataclasses sensíveis com permissões no nível da dataclass.

Lembre-se que as permissões de guest se aplicam a toda sessão. Sem privilégio de bloqueio, uma entrada inválida descartada pelo 4D deixa o recurso aberto em modo irrestrito.

Use estas configurações como ponto de partida:

  • Desenvolvimento: Defina ambas as propriedades como false para facilitar o acesso durante o desenvolvimento e depuração. Aplique restrições gradualmente conforme necessário.
  • Produção: Defina restrictedByDefault e forceLogin como true para que os usuários precisem autenticar e o acesso aos recursos seja explicitamente concedido.

Erros de permissão​

Arquivo Roles_Errors.json​

O 4D analisa o roles.json na inicialização. Reinicie o aplicativo para que as alterações tenham efeito.

Se a análise falhar, o 4D grava os erros em Roles_Errors.json na pasta Logs do projeto. Ele exclui este arquivo após o roles.json ser corrigido.

Verifique na inicialização, especialmente em produção, se existe o arquivo Roles_Errors.json. Sua presença indica erro de análise, e as permissões podem não ser aplicadas como esperado. Você pode escrever, por exemplo:

/Sources/DatabaseMethods/onStartup.4dm
Se (Not(File("/LOGS/"+"Roles_Errors.json").exists))
...
Senão // você pode impedir o projeto de abrir
ALERT("O arquivo roles.json está malformado ou contém inconsistências, o aplicativo será encerrado.")
QUIT 4D
Finalizado, se

Erros de permissão são retornados da seguinte forma:

Caminhoread / create / update / drop recusadoexecute recusado
RESTHTTP 401 com mensagemHTTP 500 com mensagem (singleton: "Bad permission...")
Código (sessão web)Leitura: erro 1557 (dataclass) ou 1607 (atributo). Criação: erro 1608 ao atribuir um atributo a uma nova entidade se create for restrito por permissão; em modo restrito sem permissão, save() retorna success: false e statusText: "Permission Error". Update/drop: erro 1557 ao carregar a entidade (ambos requerem read).Erro 1561

Exemplo​

Este exemplo concede um conjunto amplo de permissões via privilégio manager, enquanto o privilégio payroll concede acesso de leitura à dataclass sensível Salaries.

roles.json
{
"forceLogin": true,
"restrictedByDefault": true,
"privileges": [
{"privilege": "payroll", "includes": []},
{"privilege": "manager", "includes": []}
],
"roles": [
{"role": "administrator", "privileges": ["manager", "payroll"]}
],
"permissions": {
"allowed": [
{
"applyTo": "ds",
"type": "datastore",
"read": ["manager"],
"create": ["manager"],
"update": ["manager"],
"drop": ["manager"],
"execute": ["manager"]
},
{
"applyTo": "Salaries",
"type": "dataclass",
"read": ["payroll"]
}
]
}
}

Aqui estão as regras resultantes:

SessãoLer SalariesCriar SalariesAtualizar/excluir SalariesLer outras dataclasses
managerRecusado (a permissão read de Salaries substitui a permissão do datastore)Permitido (herdado do datastore)Recusado (read é obrigatório)Permitido
payrollPermitidoRecusado (a permissão do datastore é concedida apenas a manager)RecusadoRecusado
função administratorPermitidoPermitidoPermitidoPermitido

A permissão read de Salaries substitui a permissão read do datastore, então apenas manager não pode ler essa dataclass. A função administrator recebe as permissões combinadas de manager e payroll.