Framework para Controle de Regras de Acesso de Usuários inspirado no conceito RBAC.
This is called safety and not security intentionally because its creator wanted it that way.
Basta registrar no Library Path do seu Delphi o caminho da pasta SRC da Biblioteca ou utilizar o Boss (https://github.com/HashLoad/boss) para facilitar ainda mais, executando o comando
boss install https://github.com/bittencourtthulio/safety4d
Para utilizar o Safety4D você deve adicionar a uses
Safety4D
O Safety4D foi baseado no conceito de RBAC ( role-based access control) https://pt.wikipedia.org/wiki/Controle_de_acesso_baseado_em_fun%C3%A7%C3%B5es
Ele se baseia em uma estrutura JSON de configuração para definição das permissões, inspirada na estrutura utilizada pelo Windows Azure.
https://docs.microsoft.com/pt-br/azure/role-based-access-control/overview
Abaixo o exemplo de um arquivo de configuração
{
"resources": {
"safety4d": {
"users": {
"actions": {
"read": {
"description": "read-only",
"errormsg": "not permit"
},
"write": {
"description": "read-write",
"errormsg": "not write data"
},
"delete": {
"description": "delete-data",
"errormsg": "not delete data"
},
"view": {
"description": "view data",
"errormsg": "not view data"
}
}
}
}
},
"groupPermission": {
"{4D62E4C3-C73D-488A-8518-03A9545B5611}": {
"key": "Gerente",
"description": "Permissoes completa de gestao do Sistema",
"Actions": [
"users.write"
],
"NotActions": [
"*"
]
},
"{C188D1AB-EC28-4380-96E0-D1B13A29A8B3}": {
"key": "Comercial",
"description": "Permissoes de Recursos Comerciais",
"Actions": [
"*"
],
"NotActions": [
"users.delete",
"users.write"
]
}
},
"userKeys": {
"{34C940ED-50E7-4CE3-B701-03CF1E15F28B}": {
"description": "Fulano de Tal",
"permissionGroups": [
"{4D62E4C3-C73D-488A-8518-03A9545B5611}"
]
},
"{96B4C46F-0EBB-443B-B309-09C81844406E}": {
"description": "Beltrano",
"permissionGroups": [
"{C188D1AB-EC28-4380-96E0-D1B13A29A8B3}"
]
}
}
}
Abaixo vou detalhar cada bloco do JSON acima explicando o objetivo e a aplicação de cada recurso.
Neste bloco você vai cadastrar a sua aplicação, os recursos dela e as ações que você deseja validar.
"resources": {
"safety4d": {
"users": {
"actions": {
"read": {
"description": "read-only",
"errormsg": "not permit"
},
"write": {
"description": "read-write",
"errormsg": "not write data"
},
"delete": {
"description": "delete-data",
"errormsg": "not delete data"
},
"view": {
"description": "view data",
"errormsg": "not view data"
}
}
}
}
},
No exemplo acima, estamos cadastrando a aplicação chamada safety4d, o recursos chamados users e as ações disponíveis neste recurso read, write, delete, view . Você pode cadastrar quantas ações desejar para um recurso.
Neste bloco você cria os grupos de permissão que serão atribuidos aos usuários, definindo quais recursos e actions podem e não podem ser acessados pelos usuários do grupo.
No bloco Actions você define todos os recursos e actions que os participantes do grupo terão acesso, e no bloco NotActions você define todos os recursos e actions que estarão bloqueados para os participantes do grupo.
Utilizando o caracter "*" no bloco Actions você está liberando o acesso a todos os recursos exceto aqueles que estiverem especificados na sessão NotActions.
Utilizando o caracter "*" no bloco NotActions você está bloqueando o acesso a todos os recursos exceto aqueles que estiverem especificados na sessão Actions.
"groupPermission": {
"{4D62E4C3-C73D-488A-8518-03A9545B5611}": {
"key": "Gerente",
"description": "Permissoes completa de gestao do Sistema",
"Actions": [
"users.write"
],
"NotActions": [
"*"
]
},
"{C188D1AB-EC28-4380-96E0-D1B13A29A8B3}": {
"key": "Comercial",
"description": "Permissoes de Recursos Comerciais",
"Actions": [
"*"
],
"NotActions": [
"users.delete",
"users.write"
]
}
},
No exemplo acima cadastramos 2 grupos de permissões distindos, no primeiro grupo Gerente definimos em Actions que os participantes desse grupo só podem acessar o recurso users executando a ação write e o caracter "*" na sessão NotActions sinaliza que todas as demais funções estão bloqueadas.
No segundo grupo todas as Actions estão liberadas, exceto as que estão descritas no bloco NotActions.
Neste bloco você cadastra as chaves referentes aos usuários do sistema, atribuindo a eles as keys dos Grupos de Permissões que ele participa.
"userKeys": {
"{34C940ED-50E7-4CE3-B701-03CF1E15F28B}": {
"description": "Fulano de Tal",
"permissionGroups": [
"{4D62E4C3-C73D-488A-8518-03A9545B5611}"
]
},
"{96B4C46F-0EBB-443B-B309-09C81844406E}": {
"description": "Beltrano",
"permissionGroups": [
"{C188D1AB-EC28-4380-96E0-D1B13A29A8B3}"
]
}
}
Você pode utilizar os recursos do proprio componente para criar seu arquivo de configuração ou criar manualmente e carrega-lo no componentes.
var
aJson : TJsonObject;
begin
aJson := TJSONObject.ParseJSONValue('SEU JSON') as TJsonObject;
try
TSafety4D.New.LoadConfig(aJson);
finally
aJson.Free;
end;
Uma vez estando com as configurações do arquivo carregadas no componente TSafety4D, você pode utilizar os recursos de validação.
TSafety4D.New
.Validation
.userKey('CHAVE DO USERKEY')
.application('APPLICATION DO RECURSO')
.resource('NOME DO RECURSOS')
.action('ACTION A SER EXECUTADA')
.validate;
Abaixo o exemplo utilizando os dados do arquivo de configuração que mostramos acima, verificando se um usuário especifico possuí a permissão para escrever no recurso de users.
TSafety4D.New
.Validation
.userKey('{34C940ED-50E7-4CE3-B701-03CF1E15F28B}')
.application('safety4d')
.resource('users')
.action('write')
.validate;
O Safety4D trabalha com uma instancia Singleton, ou seja, a mesma instancia é compartilhada em toda a aplicação, com isso algumas configurações você pode deixar por default como por exemplo userKey e application que provavelmente não irão mudar em uma sessão de usuário durante o uso.
Sendo assim você pode por exemplo na instancia principal da sua aplicação já deixar esses valores setados.
TSafety4D.New
.Validation
.userKey('{34C940ED-50E7-4CE3-B701-03CF1E15F28B}')
.application('safety4d');
E durante o uso nas demais telas você não precisa mais passar essas informações para realizar a validação de um recurso.
TSafety4D.New
.Validation
.resource('users')
.action('write')
.validate;
A função validade retorna um boolean sinalizando se o acesso é permitido ou não, porém você pode tratar a permissão fazendo com que o TSafety4D dispare uma excessão com a mensagem do que falhou na validação, não necessitando assim de estrutura condicional para validar o acesso.
TSafety4D.New
.configurations
.exceptions(True)
.&end
.Validation
.userKey('{34C940ED-50E7-4CE3-B701-03CF1E15F28B}')
.application('safety4d')
.resource('users')
.action('write')
.validate;
Você pode criar o arquivo de configuração manualmente e carrega-lo no componente ou utilizar o proprio componente para definir as configurações.
TSafety4D
.New
.resources
.registerResources
.resourcesGroupName
.add('newapplication')
.providerName
.add('users')
.actions
.add('read')
.description('read-only')
.errormsg('not permit')
.&end
.add('write')
.description('read-write')
.errormsg('not write data')
.&end
.add('delete')
.description('delete-data')
.errormsg('not delete data')
.&end
.add('view')
.description('view data')
.errormsg('not view data')
.&end
.&end
.&end
.&end
.&end
.&end
.groupPermission
.groupRegister
.add('Operador')
.description('Funções de Operador do Sistema')
.actions
.add('users.view')
.&end
.notActions
.add('*')
.&end
.&end
.&end
.userKey
.registerUserKey
.add('Fulano de Tal')
.addPermission('{96B4C46F-0EBB-443B-B309-09C81844406E}')
.&end
.&end
.&end;
Utilizando o código abaixo você carrega toda a configuração do componentes para um TJsonObject.
var
aJsonSafety4D : TJsonObject;
begin
aJsonSafety4D := TJSONObject.Create;
try
TSafety4D.New.getConfig(aJsonSafety4D);
Memo1.Lines.Add(aJsonSafety4D.Format);
finally
aJsonSafety4D.Free;
end;
Você pode utilizar o recursos abaixo para salvar as configurações diretamente no disco.
TSafety4D.New.SaveToStorage();
Crie a estrutura e salve ela no seu banco de dados em um campo de texto e carregue toda vez que abrir a aplicação ou tiver alguma mudança nas configurações para o componente.