Ir para o conteúdo

Introdução ao App Builder - Apêndice D: Segurança no App Builder (Avançado)

Este é o quarto e último apêndice da série de tutoriais Introdução ao App Builder. Estes apêndices complementam as lições da série e fornecem informações mais detalhadas sobre conceitos apresentados.

Nesta lição, exploraremos a camada de segurança do App Builder, a área onde controlamos quem pode acessar nossa aplicação e quais partes de seus dados cada usuário tem permissão para visualizar ou alterar.

Funções

Funções são a forma como o App Builder organiza permissões para uma fonte de dados. Uma função pode receber permissões de Leitura, Inserção, Atualização e Exclusão em uma tabela ou objeto de negócio, e os usuários obtêm suas funções indiretamente, através da associação em um ou mais grupos de segurança. Grupos organizam usuários; funções organizam permissões. Consulte Funções para uma explicação completa do que é uma função, ou Privilégios e permissões para saber como cada permissão afeta o que um usuário pode visualizar e fazer.

Vamos criar um conjunto de funções para nossa fonte de dados Northwinds que reflitam funções de trabalho comuns em uma empresa: Superusuário, Somente leitura, Operações, RH e Vendas. Cada uma introduz uma forma diferente de conceder permissões, desde aceleradores amplos até controle preciso, objeto por objeto.

Superusuário

Crie uma função de Superusuário seguindo estas etapas:

  1. Em App Workbench > Data Sources, selecione a fonte Northwinds (Default).

  2. Na seção Business Logic Layer, clique em Roles. A caixa de diálogo Roles é aberta.

  3. Clique em + Superuser. O App Builder cria automaticamente uma função chamada Superuser com permissões totais em todas as tabelas e objetos de negócio na fonte de dados.

Dica

+ Superuser é um acelerador: em vez de criar uma função e depois conceder Leitura, Inserção, Atualização e Exclusão um objeto por vez, ele cria a função e concede as quatro permissões em tudo de uma só vez.

Somente leitura

Agora, crie uma função de Somente leitura seguindo estas etapas:

  1. Clique em + Role.

  2. No campo Name, insira Read Only.

  3. No campo Description, insira uma descrição como View-only access to all Northwinds data.

  4. Clique em Save.

  5. Expanda o acordeão Tables e clique em Grant Read para dar à função Read Only acesso de leitura a todas as tabelas de uma só vez.

  6. Expanda o acordeão Business Objects e depois clique em Grant Read para fazer o mesmo para todos os objetos de negócio.

Dica

A caixa de diálogo Roles oferece vários aceleradores para conceder permissões em massa:

  • Grant Full concede todas as permissões (Leitura, Inserção, Atualização e Exclusão) em todas as tabelas ou objetos de negócio de uma só vez, e Grant Read concede permissão de leitura da mesma forma.
  • Grant on Create concede automaticamente uma nova permissão a uma função sempre que uma nova tabela ou objeto de negócio é criado, para que você não tenha que revisitar a caixa de diálogo Roles toda vez que seu modelo de dados cresce.
  • As caixas de seleção Default Permissions definem quais permissões Grant on Create aplica automaticamente e quais permissões Grant Default concede a tabelas e objetos de negócio existentes.
  • Revoke All remove todas as permissões que a função tem em todas as tabelas ou objetos de negócio existentes de uma só vez.

Consulte Table and business object permissions para a referência completa.

Operações

A função de Operações gerencia o inventário principal, relacionamentos com fornecedores e cumprimento de pedidos que mantêm o negócio funcionando nos bastidores. Ela supervisiona categorias de produtos, atualiza preços e níveis de estoque, gerencia contatos de fornecedores e atribui transportadoras para entregar pedidos dos clientes.

  1. Clique em + Role.

  2. No campo Name, insira Operations.

  3. Clique em Save.

  4. Clique no ícone Pages na linha de Operations para outra forma de acelerar a criação de funções: em vez de conceder permissões tabela por tabela, você seleciona quais páginas uma função precisa e o App Builder concede as permissões subjacentes das quais essas páginas dependem.

  5. Selecione as páginas Suppliers, Supplier, Shippers, Shipper, Products, Product e Categories, e conceda acesso total (Read, Insert, Update e Delete) a todas elas.

  6. Selecione as páginas Home, Customers, Customer, Orders, Order, Employees e Employee, e conceda apenas acesso Read a todas elas, já que Operations precisa visualizar esses dados sem poder alterá-los.

HR

A função HR gerencia registros de funcionários, suas atribuições regionais e a estrutura organizacional de relatórios. Ela requer acesso preciso e granular em vez de concessões amplas de tabela ou nível de página.

  1. Clique em + Role.

  2. No campo Name, insira HR.

  3. Clique em Save.

  4. No painel da função, clique em + Permission para adicionar objetos específicos um de cada vez.

  5. Adicione as regras Employee (Source), Region (Source), Region (List) e Employee (Network) para conceder acesso total à HR a cada uma. Adicionar uma permissão dessa forma concede acesso total (Read, Insert, Update e Delete) por padrão.

Hora de praticar: Criar a função Sales

A função Sales precisa gerenciar clientes e pedidos, visualizar dados de produtos, categorias, transportadores e funcionários, e ver os relatórios que criamos. Ela não deve ter acesso a dados administrativos como fornecedores ou a tabela de parâmetros.

Usando o mesmo acelerador de ícone Pages que usou para Operations, crie uma função Sales com o seguinte acesso:

  • Acesso total às páginas Customers, Customer, Orders e Order.
  • Acesso Read às páginas Products, Product, Categories, Shippers, Shipper, Employees, Employee e Order Total by Employee.

Não selecione as páginas Suppliers, Supplier ou Parameter, para que Sales não tenha acesso a elas.

Grupos de aplicativos

Quando funções existem, as permissões se tornam restritivas por padrão: um usuário recebe as permissões de uma função apenas se seus grupos concederem essa função. Como sua conta de usuário ainda não está em nenhum grupo, criar as funções acima bloqueia seu acesso ao próprio aplicativo, a menos que você as conecte a usuários reais. Consulte Como as funções afetam o acesso ao aplicativo para entender por que isso acontece.

  1. Na página Roles, clique em Application Groups.

  2. Clique em Create.

  3. No campo Name, use o padrão [App Name] [Role], por exemplo Northwinds Superuser. No campo Description, descreva quem pertence ao grupo.

  4. Clique no ícone de marca de seleção para salvar.

  5. No painel Roles, clique em Grant ao lado da função Superuser para conectá-la ao grupo de aplicativo Northwinds Superuser.

Importante

Prefira grupos de aplicativos em vez de grupos regulares quando a finalidade de um grupo é específica para um aplicativo. Os grupos de aplicativos são entregues junto com o aplicativo como parte de uma versão (LP), portanto são automaticamente levados aos ambientes a montante como QA e Produção. Os grupos regulares existem por ambiente do App Builder e não se movem com o aplicativo. Consulte Usuários e grupos para saber mais sobre a diferença.

Hora de praticar: Criar os grupos de aplicativos restantes

Repita as etapas acima para criar um grupo de aplicativo para cada uma das outras funções que você criou: Read Only, Operations, HR e Sales.

Por fim, adicione-se ao grupo Northwinds Superuser para não perder acesso ao aplicativo que está construindo:

  1. Navegue para IDE > User Management > Groups.

  2. Localize o grupo Northwinds Superuser e clique em + Membership.

  3. Selecione seu usuário.

  4. Clique no ícone de marca de seleção para salvar.

Agora você deve ter permissões totais novamente, pois seu usuário pertence ao grupo Northwinds Superuser, que concede a você a função Superuser.

Reach

Reach é a implementação de segurança em nível de linha do App Builder. Enquanto as funções que acabamos de criar controlam quais operações um usuário pode executar em um objeto de dados como um todo, Reach controla quais linhas desse objeto de dados um usuário pode ver ou afetar em primeiro lugar. Reach é implementado pelo mecanismo de negócios do App Builder, portanto funciona da mesma forma independentemente do banco de dados subjacente.

Reach é construído a partir de três conceitos:

  • Regra Reach: Uma regra de negócio comum, como as que criamos no Apêndice B, que determina quais segmentos dos dados um usuário pode acessar. As regras Reach normalmente usam a função mvSQL who() para correlacionar o usuário atual com os dados que ele pode ver.

  • Token Reach: A coluna única selecionada em uma regra Reach, identificada pelo tipo de uso de coluna Reach Token, que identifica um segmento de dados, como uma região ou uma unidade de negócio.

  • Registro Reach: A configuração que anexa uma regra Reach a um objeto de dados, especificando qual coluna desse objeto de dados corresponde ao token da regra Reach e, opcionalmente, qual função a restrição se aplica.

Lembre-se da Lição 5 que adicionamos uma coluna RegionID à nossa tabela Employee e atribuímos alguns funcionários à East Coast Region e outros à West Coast Region. Usaremos essa mesma configuração para restringir a página Employees para que cada usuário veja apenas os funcionários de sua própria região.

Primeiro, precisamos de uma forma de identificar qual registro de funcionário corresponde ao usuário atualmente conectado. Usaremos o UserID do funcionário em vez do nome de usuário, já que um nome de usuário pode mudar ao longo do tempo, enquanto um UserID permanece constante durante a vida da conta.

  1. Vincula a fonte de dados Vinyl (Sealed) integrada à sua aplicação para que você possa usar seus objetos de dados públicos: em App Workbench > Data Sources, clique em + Data Source. A caixa de diálogo Add a Source to your application abre.

  2. Selecione Link to existing source, depois localize e selecione Vinyl (Sealed) na lista de fontes de dados existentes.

  3. Clique em Link Sources.

  4. Clique em Done.

Agora, vamos dar à tabela Employee uma coluna correspondente.

  1. Em App Workbench > Tables, localize a tabela Employee e abra-a.

  2. Clique em + Column.

  3. Dê à nova coluna o nome UserID. Na seção Data Types, certifique-se de que o campo Logical tem Unique ID selecionado, o que define automaticamente o campo Physical como UUID.

  4. Clique em Save.

  5. Em App Workbench > Rules, localize a regra Employee (Source) e abra-a.

  6. Na aba Tables, localize a coluna UserID e marque a caixa de seleção para incluí-la.

Em vez de digitar esse valor manualmente, vamos adicionar um controle para que ele possa ser definido pela interface do usuário, da mesma forma como você precisaria fazer em um ambiente real de produção.

  1. Em App Workbench > Pages, localize a página Employee e abra-a.

  2. No painel Page Panel Layout, clique em Controls.

  3. Clique em + Control.

  4. No menu Column, selecione UserID e clique em Next.

  5. Em Source, selecione User_Read, o objeto de dados público exposto pela fonte de dados Vinyl (Sealed) que você vinculou acima. A seleção Key (Column) deve ser UserId e o Title (Column) deve ser UserName.

  6. Clique em Next, depois em Finish.

  7. Navegue até a página Employees, abra qualquer funcionário já atribuído a uma região e use o novo campo para selecionar o usuário com o qual você faz login no App Builder.

Leitura complementar

User_Read é um dos vários objetos de dados públicos que o App Builder disponibiliza para uso em suas regras. Consulte User_Read e Access to public data objects para saber mais.

Agora, vamos criar a regra Reach.

  1. Em App Workbench > Rules, clique em + Rule.

  2. No campo Name, insira Employee (Region Access).

  3. No campo Purpose, selecione Reach.

  4. No campo Target, selecione Employee.

  5. Clique em Create.

  6. Na aba Tables, selecione RegionID e UserID, além da coluna de chave primária EmployeeID que já está selecionada.

  7. Na aba Where, clique em + Where Clause. No campo Left Expression, digite E.UserID, no campo Operator, selecione =, e no campo Right Expression, digite who('userid'). Clique em Save.

  8. Na aba Columns, clique duas vezes na coluna RegionID. Na seção Advanced, defina seu Column Usage Type como Reach Token. Clique em Save.

  9. Clique em Results no painel Rule para confirmar que a regra retorna uma única linha, contendo a região do registro de funcionário que você selecionou anteriormente.

Agora, vamos registrar essa regra de Reach para restringir o objeto de negócio Employee (Source).

  1. Em App Workbench > Rules, localize e abra a regra Employee (Source).

  2. No painel Rule, clique em More > Edge Case. A caixa de diálogo Edge Case Settings é aberta.

  3. Clique em Reach. A caixa de diálogo Reach Registration é aberta.

  4. Clique em Create.

  5. No campo Rule, selecione Employee (Region Access).

  6. No campo Binding Column, selecione RegionID.

  7. Deixe o campo Role em branco por enquanto, para que a restrição se aplique a todos os usuários, incluindo você, enquanto testamos. Certifique-se de que Active esteja marcado.

  8. Clique em Save.

Acesse a visualização da página Employees. Agora você deve ver apenas funcionários que compartilham uma região com o registro de funcionário que você selecionou, em vez da lista completa.

Nota

Em uma aplicação real, você provavelmente não gostaria que essa restrição afetasse os administradores. Agora que a regra foi confirmada como funcionando, edite o registro de Reach novamente e defina seu campo Role como a função Sales que criamos anteriormente. Dessa forma, apenas usuários cujos grupos lhes concedem a função Sales são restritos por região, enquanto usuários com a função Superuser mantêm visibilidade completa.

Nota

Registrar uma regra de Reach em um objeto de negócio apenas restringe esse objeto específico, não toda regra construída sobre sua tabela subjacente. Por exemplo, a regra Employee (Network) que construímos em Appendix C também consulta a tabela Employee, mas como é um objeto de negócio separado de Employee (Source), não é restringida por uma regra de Reach registrada apenas em Employee (Source). Para restringir toda regra construída sobre uma tabela, registre a regra de Reach no nível da tabela em vez de em um objeto de negócio individual.

Hora de praticar: estenda o acesso por região aos clientes

Funcionários não são os únicos dados da Northwinds que poderiam se beneficiar do acesso baseado em região. Vamos aplicar a mesma restrição à tabela Customer.

  1. Seguindo os passos usados acima para a tabela Employee, adicione uma coluna RegionID à tabela Customer, adicione-a à regra Customer (Source) e adicione um controle de lista Region (originário de Region (List)) à página pop-up Customer. Use o novo controle para atribuir uma região a alguns registros de cliente.

  2. Crie uma nova regra de Reach chamada Customer (Region Access), com Purpose definido como Reach e Target definido como Customer. Na aba Tables, clique em + Tables para adicionar a tabela Employee, unida a Customer em RegionID.

  3. Reutilize a mesma cláusula Where e tipo de uso de coluna Reach Token da regra Employee (Region Access), dessa vez selecionando RegionID da tabela Employee. Combinada com a junção, a regra agora retorna apenas clientes que compartilham uma região com o funcionário atualmente conectado.

  4. Registre a nova regra no objeto de negócio Customer (Source), dessa vez vinculando-a à coluna RegionID própria da tabela Customer.

  5. Acesse a visualização da página Customers para confirmar que apenas clientes de sua região estão visíveis.

Dica

Em App Workbench, navegue até a aba Roles. Selecionar uma função da grade mostra seu diagrama de página à direita; páginas com segurança em nível de linha aplicada mostram um ícone de mão, facilitando a visualização rápida de quais páginas dessa função são restritas por Reach.

Leitura complementar

Este exemplo apenas toca na superfície do que o Reach pode fazer. Para uma descrição completa dos conceitos, cenários suportados e limitações do Reach, consulte Reach.

Block

O tipo de uso de coluna Block impede que uma linha seja editada, excluída ou ambas. Diferentemente das funções, que se aplicam a um objeto de dados inteiro, e do Reach, que controla a visibilidade da linha, o Block controla o que um usuário pode fazer em uma linha que já consegue visualizar. Um objeto de dados pode usar apenas uma coluna Block, e seu valor determina a restrição:

Valor da célula Descrição
1 Impede a edição dessa linha.
2 Impede a exclusão dessa linha.
3 Impede tanto a edição quanto a exclusão da linha.
Qualquer outro valor Não impede nada.

Você pode adicionar uma coluna Block em dois níveis diferentes, e o local onde você a adiciona determina o alcance da restrição. Adicioná-la a uma tabela na camada de dados aplica a restrição globalmente, em todos os lugares onde os dados dessa tabela são usados em todo o aplicativo. Adicioná-la como uma expressão em um objeto de negócio na camada de lógica, como faremos abaixo, aplica a restrição apenas onde esse objeto de negócio específico é usado.

Em vez de retornar esses números diretamente, também é possível usar a função mvSQL BlockOption(), que aceita os valores mais legíveis None, Edit, Delete e EditAndDelete.

Após um pedido ser enviado, seus itens de linha não devem mudar mais. Vamos bloquear a edição e exclusão de linhas OrderDetail para qualquer pedido que já tenha uma ShippedDate.

  1. Em App Workbench > Rules, localize e abra a regra OrderDetail (Source).

  2. Na guia Tables, clique em + Tables e adicione a tabela Order.

  3. Na guia Joins, o App Builder já deve ter criado uma junção interna entre OrderDetail e Order em OrderID. Se não tiver, crie-a.

  4. Na guia Columns, clique em + Column. No campo Column or Expression, insira IIF(O.ShippedDate IS NOT NULL, BlockOption(EditAndDelete), BlockOption(None)). No campo Alias, insira Block.

  5. Clique em Save.

  6. Clique duas vezes na nova coluna Block. Na seção Advanced, defina seu Column Usage Type como Block. Clique em Save.

Visite a visualização da página Orders e selecione um pedido que já tenha uma ShippedDate. Em seu painel Order Details, os ícones de edição e exclusão não devem mais aparecer para nenhuma linha. Selecione um pedido que ainda não foi enviado e esses ícones devem estar disponíveis como de costume.

Hora de praticar: Bloquear o próprio pedido

Os itens de linha não são os únicos registros que não devem mudar após o envio. Aplique a mesma lógica diretamente à regra Order (Source): adicione uma coluna Block com a expressão IIF(ShippedDate IS NOT NULL, BlockOption(EditAndDelete), BlockOption(None)) e defina seu Column Usage Type como Block. Como ShippedDate já pertence à tabela Order, nenhuma junção é necessária desta vez. Teste seus resultados na visualização da página Orders: pedidos enviados não devem mais mostrar seus próprios ícones de edição e exclusão.

Capability bindings

Capability bindings são um tipo especializado de binding que vinculam o estado funcional de um painel filho aos dados de um painel pai ou objeto de dados da página. Podem ser usados para ocultar ou desabilitar controles, de forma semelhante ao Block, mas com uma vantagem importante: os capability bindings também podem afetar o botão Create de um painel. Isso é algo que o Block não consegue fazer, já que esse botão existe independentemente de qualquer linha específica.

Uma coluna com capability binding pode retornar valores diferentes para controlar o estado de um controle vinculado:

Valor da célula Descrição
1 Oculta o controle.
2 Desabilita o controle, deixando-o visível, mas inutilizável.
Qualquer outro valor Reverte ao comportamento padrão do controle.

Vamos usar isso para desativar o botão Create no painel Order Details sempre que o pedido pai já tiver sido enviado, impedindo que novos itens de linha sejam adicionados a um envio que já saiu.

  1. Em App Workbench > Rules, localize e abra a regra Order (Source).

  2. Na aba Columns, clique em + Column. No campo Column or Expression, insira IIF(ShippedDate IS NOT NULL, 2, 0). No campo Alias, insira LockNewDetails.

  3. Clique em Save.

  4. Abra a página Orders e selecione Action Drawer > Live Designer.

  5. Clique no ícone da coluna de vinculação no painel Order Details. A caixa de diálogo Binding Columns abre:

    Binding columns

  6. Clique em + Binding e defina o campo Type como Capability.

  7. No campo Parent, selecione LockNewDetails.

  8. No campo Intrinsic Event, selecione Insert.

  9. Clique em Save.

Visite a visualização da página Orders e selecione um pedido enviado. O botão Create no painel Order Details agora deve estar desativado. Selecione um pedido que não foi enviado e o botão deve estar clicável novamente.

Hora de praticar: Ocultar em vez de desativar

As vinculações de capacidade suportam outros status além de desativar um controle. Um valor de 1 oculta um controle completamente em vez de desativá-lo. Altere a expressão LockNewDetails para IIF(ShippedDate IS NOT NULL, 1, 0) e teste seus resultados: o botão Create no painel Order Details agora deve desaparecer completamente em pedidos enviados, em vez de permanecer visível mas inutilizável.

Formatação condicional

As vinculações de Block e capacidade cobrem as formas integradas com que os usuários interagem com um registro: os ícones de edição e exclusão e o botão Create de um painel. No entanto, qualquer botão conectado a um evento personalizado, como os botões Quantity Plus e Quantity Minus que adicionamos em Appendix B, ignora ambos. Nem Block nem o Intrinsic Event de uma vinculação de capacidade se aplica a um evento personalizado, portanto esses botões continuam funcionando mesmo em pedidos enviados, permitindo que os usuários alterem uma Quantity que não deveria mais ser editável.

A formatação condicional permite ocultar ou desativar um controle com base no valor de qualquer coluna, independentemente de qual evento ele está conectado. Vamos usá-la para desativar o botão Quantity Minus depois que um pedido for enviado.

No entanto, a coluna ShippedDate pertence à tabela Order, não a OrderDetail, e o exercício Block acima apenas a referenciou dentro de uma expressão em vez de adicioná-la como uma coluna por direito próprio. Como o botão Quantity Minus fica no painel Order Details, que é originário de OrderDetail (Source), adicione primeiro ShippedDate àquela regra para que fique disponível para formatação condicional.

  1. Em App Workbench > Rules, localize e abra a regra OrderDetail (Source).

  2. Na aba Tables, localize a tabela Order, já associada durante o exercício Block acima, e marque a caixa de seleção da coluna ShippedDate.

  3. Clique em Save.

  4. Abra a página Orders e selecione Action Drawer > Live Designer.

  5. Selecione o botão que executa o evento Quantity Minus.

  6. Clique em More > Styles.

  7. Clique em + Conditional Formatting.

  8. No campo Source Column, selecione ShippedDate.

  9. No campo Operator, selecione Is not Null.

  10. No campo State, selecione Disabled.

  11. Clique em Save.

Visite a visualização da página Orders e selecione um pedido enviado. O botão Quantity Minus agora deve estar desativado. Selecione um pedido que não foi enviado e o botão deve estar clicável novamente.

Hora de praticar: Estender a formatação condicional

Repita as etapas acima para o botão que executa o evento Quantity Plus.

Depois, aplique a mesma restrição ao botão Delete Order Details no painel Orders, desta vez configurando seu State como Hidden em vez de Disabled, para que você possa ver como os dois estados diferem. Após um pedido ser enviado, o botão deve desaparecer completamente em vez de permanecer visível mas inutilizável.

Aprendizado adicional

Isto conclui este aprofundamento nos detalhes da camada de segurança do App Builder. Se você ainda não fez, veja o Apêndice A para uma análise mais detalhada da camada de dados, o Apêndice B para a camada de negócios ou o Apêndice C para a camada de interface.

Para continuar aprendendo sobre o App Builder, visite a Jitterbit University.