How to create a permissions control system

Asked

Viewed 23,882 times

7

I have a PHP/HTML system and want to deploy a permission system.

It would work as follows:

1) I have some pages that some features can only be seen for higher positions. Example: I have a search page, for a normal user, I want him to search only by name. Already a manager, would have several filters available.

2) Have some page to set these permissions. Using the example of the search: Administrator goes on this page and arrow given user to also be able to search for Cpf.

I don’t want a system ready. I want some idea where to go, what to look for, if there is any framework.

  • 1

    Ziad.ali is here one of several ways to do this. Good studies.

  • 1

    @Ziad.ali just to not let you down I suggest reading these topics: Creating access control with PHP and Mysql and How to create a Login System with Permission Levels

  • 1

    @Kaduamaral The question is reopened. Ziad, even then it would be cool if you [Dit] the question is to add more information, as if your system already has user registration, if you consider user groups, if the login and authentication part already exists and how it was implemented, what database used, etc.

  • Since the question is old, the answer will be new... The way forward would be to use PHP with Laravel Framework, search something on the net like Laravel ACL. Check out this video : https://www.youtube.com/watch?v=hJRt0BDF0Do

4 answers

14


Creating a permission system

First we need the user table:

usuarios
  id - INT AUTO_INCREMENT PRIMARY KEY
  nome - VARCHAR
  email - VARCHAR
  senha - VARCHAR
  ativo - INT (0 - Inativo / 1 - Ativo)
  nivel - (0 - usuário comum / 1 - Administrador / 2 - Desenvolvedor / 3 - Administrador e Desenvolvedor)

If the user is an administrator or developer ignore the access validations as you see fit.

Now we have to map the system pages

paginas
  id - PIRMARY KEY -- Código único que identifique a página (pode até ser o nome do arquivo ou um INT AUTO_INCREMENT)
  arquivo - VARCHAR -- Nome do arquivo
  nome - VARCHAR
  sistema - INT -- (0 - Não / 1 - Sim) é uma página do sistema como por exemplo uma página Erro 404 / Acesso Restrito / Etc...

Save all system pages in the database, and put a variable in the file with the ID of each

Now the access table:

acesso_paginas
  usuario_id
  pagina_id
  consultar (0 - Não / 1 - Sim)
  incluir (0 - Não / 1 - Sim)
  editar (0 - Não / 1 - Sim)
  excluir (0 - Não / 1 - Sim)

Use the field consultar, to see if the user has access to this page, and the other fields you can put in the inclusion/deletion buttons and fields if the user cannot edit.

If you want each field to have a different access, for each user, you will have to map all the fields of your system, something that takes a lot of work, but could do so:

fields
  id - INT PRIMARY KEY
  nome - VARCHAR
  pagina_id

For each field of each page, save a record in the database that identifies that field.

And access:

acesso_fields
  field_id
  pagina_id
  usuario_id
  visivel (0 - Não / 1 - Sim)
  editavel (0 - Não / 1 - Sim)

Use the field visivel to display the field on the system and the editable field to enable or disable.

Rule

Whenever a user accesses a page, you search the page in the table acesso_paginas and see if he has access to that page. If the user has access, you check what type of access, and apply the appropriate rules according to the type of access. Example, if it can only query the page only display the necessary with all fields disabled.

If you are going to validate the fields, look in the table acesso_fields for ID page and search all page fields in one SELECT, and make a function to search in the returned data the field and permissions.

Example

Access to the page:

$pageid = 36;
$sql = "SELECT * FROM acesso_paginas WHERE usuario_id = {$_SESSION['user']['id']} AND pagina_id = {$pageid};"
// Receba o resultado e verifique o tipo de acesso.

if ($res['consultar'] == '0') {
   header("HTTP/1.1 401 Unauthorized");
   exit;
}

.
.
.

if ($res['excluir'] == '1') echo '<button type="button" id="excluir" class="button">Excluir</button>';

Field access:

$pageid = 36;
$sql = "SELECT * FROM acesso_fields WHERE usuario_id = {$_SESSION['user']['id']} AND pagina_id = {$pageid};"
// Receba os dados

function FieldAccess($dados){
   // Faça uma função quer percorra o array recebido do baco e retorne os devidos acessos ao campo
   // Pode usar códigos do tipo

   // 0 - Sem acesso total (não exibe campo)
   if ($dados[$x]['visivel'] == '0') return 0;  

   // 1 - Acesso visual (apenas exibe o campo, mas não permite editar o valor)
   if ($dados[$x]['visivel'] == '1' && $dados[$x]['editavel'] == '0' ) return 1; 

   // 2 - Acesso total
   // if ($dados[$x]['visivel'] == '1' && $dados[$x]['editavel'] == '1' ) return 2; 
   // Sempre retorne 2 para exibir normalmente os campos que não estiverem 
   // cadastrados no acesso do usuário
   return 2;
}

.
.
.

<?php
  $acesso = FieldAccess(348);
  if ($acesso > 0){
?>
<input type="text" name="cpf" id="cpf" placeholder="Informe o CPF"<?=($acesso == '1' ? ' readonly' : '')?>>
<?php
  }
?>




Obs.: Great care to the excessive validation of fields, because it can end up damaging the performance of the system. Use only in necessary cases.

  • Thank you very much @Kaduamaral, reading here seems to be exactly what I want. It seems a little laborious, but it would solve the problem. I will leave as a right answer here and try to implement.

  • I already use a very similar scheme in a project that I have, I just do not use the validation of individual fields, because it is really very laborious, I only use the validation of the pages (query, insert, edit, delete) that already serves me well. If you are having difficulties implementing, post here, or if necessary ask a new question, if the problem is very specific.

4

The question is wide because there are many ways to implement a permissions control system. Even so, I will try to show one of the possible paths, in general lines.

Permissions control takes into account who accesses (users and/or groups), what is accessed (pages, page parts, form fields etc) and often, as this can be accessed (for example, in the case of fields, if the access is read-only).

Taking this into account, the first step is to model your database to support these entities. At a minimum a user table, an "accessible" table (objects with controlled permission), and a permissions table relating the two, recording who has access to what.

Modeled on the basis, I would create an abstraction layer of the access control, in your case in PHP, so that it is simple for the developer to "ask" the system if a given user has access to a given object. Considering your example, when mounting the HTML of view research, you could do something like this:

if(acesso->permitido($id_usuario, 'busca_cpf')) {
    // Desenha o campo de busca por CPF
}

Of course access control should not be done only in the view. In the code that actually performs the search, it is recommended to do the same check when receiving a CPF for search, before mounting the query that brings the records by CPF. This way, if some user without access tries to cheat the system by passing a CPF, the search would not be done.

  • Like I said, these are just general lines, but I hope it helps you find a way.

  • This is a question I have, because I do the validation based on the page ID, but the file that receives the data is an abstract file that can receive data of several pages. So how would I validate when receiving the data?

  • Similarly, check that the logged-in user has access to a specific functionality (not a page) @Kaduamaral.

4

I’m working on a site in PHP that has but the least 6500 possibility of access. The principle is a "variation" of an "Assembly Language" concept and we call this Xgen.

Each page of the site has a String "Xgen" composed of values like: Example:

pagina A -> 01000
pagina B -> 00100
pagine C -> 00001

each user has a "string" of the same type. Example:

Marcello -> 01100
José -> 00001

When Marcello arrives on page A, the system gives a look at the 2 values:

Da pagina -> 01000
Do usario -> 01100

Result: Marcello has direct access on this page

But Marcello, in this example, has no access on page C

You can "ameliorate" the principle, using different values. Example:

001000 significa simplismente accesso
002000 significa accesar + editar
etc...

In my system, each Xgen has 100 values: for each page and for each Fireman (and a block admin system). I can determine access with degree, level of training, age etc.

-3

The system will consist of a simple login, validated by user and password (encrypted) against a table in the database and storing the data in the session. There will be two levels of access for our users: normal (1) and administrator (2).


Creating the Mysql Table

You can run this Mysql code to create our user table that has 7 fields: id, name, user, password, levels, active and register:

CREATE TABLE IF NOT EXISTS `usuarios` (
    `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    `nome` VARCHAR( 50 ) NOT NULL ,
    `usuario` VARCHAR( 25 ) NOT NULL ,
    `senha` VARCHAR( 40 ) NOT NULL ,
    `email` VARCHAR( 100 ) NOT NULL ,
    `nivel` INT(1) UNSIGNED NOT NULL DEFAULT '1',
    `ativo` BOOL NOT NULL DEFAULT '1',
    `cadastro` DATETIME NOT NULL ,
    PRIMARY KEY (`id`),
    UNIQUE KEY `usuario` (`usuario`),
    KEY `nivel` (`nivel`)
) ENGINE=MyISAM ;

With this you already have a table ready for our tutorial... Run this script if you want to feed the table with some test users:

INSERT INTO `usuarios` VALUES (NULL, 'Usuário Teste', 'demo', SHA1( 'demo' ), '[email protected]', 1, 1, NOW( ));

INSERT INTO `usuarios` VALUES (NULL, 'Administrador Teste', 'admin', SHA1( 'admin' ), '[email protected]', 2, 1, NOW( ));

As you can see, our password field has 40 characters and when we register test users we use SHA1(‘{senha}’) this means that we will use an encrypted password... If you want to know more about sha1 see this article: PHP encryption using md5, sha1 and Base64.


The XHTML Login form

We will now create our form which will be where the visitor will enter the data and will be sent to the validation.php page where the data will be validated (Ohh).

<!-- Formulário de Login -->
<form action="validacao.php" method="post">
<fieldset>
<legend>Dados de Login</legend>
    <label for="txUsuario">Usuário</label>
    <input type="text" name="usuario" id="txUsuario" maxlength="25" />
    <label for="txSenha">Senha</label>
    <input type="password" name="senha" id="txSenha" />
    <input type="submit" value="Entrar" />
</fieldset>
</form>

As this article is not a class on forms and POST method I will skip the part that talks about the Names of these inputs and their relationship with PHP itself.


The validation of the data

We already have the database and the login form... Now we will start to do the validation. The next codes should be placed within the.php validation that will handle the data received from the form:

First of all we need to check if the user actually filled something in the form, otherwise we send it back to the index php.:

<?php
// Verifica se houve POST e se o usuário ou a senha é(são) vazio(s)

if (!empty($_POST) AND (empty($_POST['usuario']) OR empty($_POST['senha']))) {
    header("Location: index.php"); exit;
}


?>

With this, any code that comes after this if will be sure that the data were filled in the form.

Now we will open a connection with Mysql but this connection can be done otherwise, even before if you prefer... After opening the connection we will transmit the two values entered by the visitor (user and password) to new variables and use the mysql_real_escape_string() to avoid errors in Mysql.

<?php

// Verifica se houve POST e se o usuário ou a senha é(são) vazio(s)
if (!empty($_POST) AND (empty($_POST['usuario']) OR empty($_POST['senha']))) {
    header("Location: index.php"); exit;
}

// Tenta se conectar ao servidor MySQL
mysql_connect('localhost', 'root', '') or trigger_error(mysql_error());
// Tenta se conectar a um banco de dados MySQL
mysql_select_db('usuarios') or trigger_error(mysql_error());

$usuario = mysql_real_escape_string($_POST['usuario']);
$senha = mysql_real_escape_string($_POST['senha']);

?>


Now it’s time to validate the data against the user table:

<?php

// Verifica se houve POST e se o usuário ou a senha é(são) vazio(s)
if (!empty($_POST) AND (empty($_POST['usuario']) OR empty($_POST['senha']))) {
    header("Location: index.php"); exit;
}
// Tenta se conectar ao servidor MySQL
mysql_connect('localhost', 'root', '') or trigger_error(mysql_error());
// Tenta se conectar a um banco de dados MySQL
mysql_select_db('usuarios') or trigger_error(mysql_error());
$usuario = mysql_real_escape_string($_POST['usuario']);
$senha = mysql_real_escape_string($_POST['senha']);

// Validação do usuário/senha digitados
$sql = "SELECT `id`, `nome`, `nivel` FROM `usuarios` WHERE (`usuario` = '". $usuario ."') AND (`senha` = '". sha1($senha) ."') AND (`ativo` = 1) LIMIT 1";
$query = mysql_query($sql);
if (mysql_num_rows($query) != 1) {
    // Mensagem de erro quando os dados são inválidos e/ou o usuário não foi encontrado
    echo "Login inválido!"; exit;
} else {
    // Salva os dados encontados na variável $resultado
    $resultado = mysql_fetch_assoc($query);
}

?>

Note that we are searching for records that have the user as typed by the visitor and that have a password equal to the SHA1 version of the password typed by the visitor... We also only search for user records that are active, so when you need to remove a user from the system, but you can’t just delete the record by just changing the value of the active column to zero. ;)

The generated query looks like this:

SELECT `id`, `nome`, `nivel` FROM `usuarios` WHERE (`usuario` = 'a') AND (`senha` = 'e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98') AND (`ativo` = 1) LIMIT 1

After rotating the query (query) we check if the number of results found (or not) is different from one, if it is displayed an error message accompanied by a exit which finalizes the script... If it finds only one result we have our user and we have already pulled your ID, name and access level from the database.


Saving the data in session

Now we need to save the data found in the session because they will be used later on other pages and they need to "persist" there... After saving the data in the session we will redirect the visitor to a restricted page:

if (mysql_num_rows($query) != 1) {
    // Mensagem de erro quando os dados são inválidos e/ou o usuário não foi encontrado
    echo "Login inválido!"; exit;
} else {
    // Salva os dados encontados na variável $resultado
    $resultado = mysql_fetch_assoc($query);
    // Se a sessão não existir, inicia uma
    if (!isset($_SESSION)) session_start();
    // Salva os dados encontrados na sessão
    $_SESSION['UsuarioID'] = $resultado['id'];
    $_SESSION['UsuarioNome'] = $resultado['nome'];
    $_SESSION['UsuarioNivel'] = $resultado['nivel'];
    // Redireciona o visitante
    header("Location: restrito.php"); exit;
}


Checking if the user is logged in

Our system of login is almost complete! Now we just need to check if the user is logged in to the system and if your level of access matches that of the page... Let’s now write a small PHP block at the beginning of the file restricted.php (that should only be accessed by logged in users):

<?php

// A sessão precisa ser iniciada em cada página diferente
if (!isset($_SESSION)) session_start();

// Verifica se não há a variável da sessão que identifica o usuário
if (!isset($_SESSION['UsuarioID'])) {
    // Destrói a sessão por segurança
    session_destroy();
    // Redireciona o visitante de volta pro login
    header("Location: index.php"); exit;
}

?>

<h1>Página restrita</h1>

<p>Olá, <?php echo $_SESSION['UsuarioNome']; ?>!</p>

Ready my friend! Your login system is ready to work... Let’s just make a few increments to make it more "usable"... Now you will see how to check logged in user and access level, for example for a page where only administrators can access:

<?php

// A sessão precisa ser iniciada em cada página diferente
if (!isset($_SESSION)) session_start();

$nivel_necessario = 2;

// Verifica se não há a variável da sessão que identifica o usuário
if (!isset($_SESSION['UsuarioID']) OR ($_SESSION['UsuarioNivel'] < $nivel_necessario)) {
    // Destrói a sessão por segurança
    session_destroy();
    // Redireciona o visitante de volta pro login
    header("Location: index.php"); exit;
}

?>


Logout code

The archive logout.php is so simple that you can have one line:

<?php session_start(); session_destroy(); header("Location: index.php"); exit; ?>

Or if you prefer, a longer version:

<?php
    session_start(); // Inicia a sessão
    session_destroy(); // Destrói a sessão limpando todos os valores salvos
    header("Location: index.php"); exit; // Redireciona o visitante
?>


Source: Thiago Belem

  • 3

    I think he wants to know something a little more complex than just a login system... ie quero implantar um sistema de permissão and Ter alguma página para setar essas permissões. Then I understood that even a common level user may have some privileges that others of the same level do not have.

  • Exact this Kaduamaral.

  • I agree @Kaduamaral but with better questions he will have better answers. With what I’ve been through he has a sense of how to start the idea is that it doesn’t give the answer but a way to go.

  • 1

    a ideia é essa não dar a resposta e sim um caminho para seguir. ... Otto sorry for the sincerity, but for me his post seemed more like the 'answer' and not a way forward

  • is a way for him to follow only a general approach of how to use how to do if he understood how to answer this wrong

  • but @Marcelobonifazio if you have a better way for him to follow feel like posting

  • Speak @Bacco without taking off nor for all we are here to complement.

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.