Usuários e Controle de Acesso no Laravel

Usuários e Controle de Acesso no Laravel

Continuando nossa série sobre o Laravel, vou escrever sobre usuários, segurança e controle de acesso (autenticação e sessões). Diferentemente do que fiz nos últimos artigos, não vou fazer uma referência teórica do assunto. Vamos direto para as alterações. Boa parte do que será feito já foi visto, então vou explicar em detalhes apenas o que for novidade.

Se você não acompanhou os artigos anteriores pode baixar o aplicativo que vamos utilizar neste link. Nós vamos começar com a criação de uma nova tabela no banco de dados. Depois vamos para o controle de acesso.

Antes de começarmos as modificações deste artigo, execute um composer update para atualizar as dependências. Estamos trabalhando com o Laravel 4.1 e a versão mais atual é a 4.1.30. Já está disponível a versão 4.2, mas vou deixar esta atualização para outro artigo.

Contas de Usuário

Para criarmos o controle de acesso no nosso aplicativo, precisamos ter usuários cadastrados no sistema. Vamos começar com o banco de dados.

Banco de Dados

Vamos criar uma tabela chamada usuários. Para isso vamos utilizar as migrações do Laravel (veja mais aqui). Abra o terminal e execute o seguinte comando:

Abra o arquivo criado (que estará em app/database/migrations) e coloque o seguinte conteúdo:

Vamos criar campos para email, senha, email e nome. Além disso temos um campo tipo, que usaremos para diferenciar usuários administradores (com acesso ao cadastro de usuários) e autores. Por fim também temos um campo remember_token, que é usado pelo Laravel para enviar lembretes de senha permitindo aos usuários reiniciar suas senhas.

Para conseguirmos enviar o lembrete de senhas também precisamos de uma tabela para guardar os tokens. para criar a migração que vai criar esta tabela execute o comando:

O Laravel vai criar a migração já com o conteúdo preenchido, portanto não é necessário nenhuma modificação. Vamos executar as migrações executando:

Model

Precisamos também criar um model para a tabela de usuário. Na instalação padrão do Laravel já existe um model chamado User.php, para ser utilizado. Para manter a lógica da nossa aplicação em português, eu preferi chamar a tabela de usuarios ao invés de user, além de usar senha no lugar de password. Por isso vamos customizar esse model. Primeiro renomeie ele para Usuario.php.

Neste model temos a implementação das interfaces UserInterface e RemindableInterface. Como nós alteramos o nome do model padrão para autenticação, precisamos alterar o arquivo de configuração app/config/auth.php.

Altere apenas a chave model para identificar o nosso novo model.

Controle de Acesso

Database Seeding

Agora que temos a tabela criada, vamos inserir alguns dados nessa tabela. Precisamos que pelo menos um usuário seja criado automaticamente, porque depois que finalizamos o controle de acesso precisamos fazer login para alterar os usuários. Ou seja, se você instalar esse código em um novo computador, não conseguirá criar nenhum usuário. Isso é chamado de database seeding, algo como semear o banco de dados. Abra o arquivo app/database/seeds/DatabaseSeeder.php.

Esse código vai inserir um usuário somente quando não houver nenhum usuário no banco de dados. Nesse código você pode ver o método Hash::make(). Este método vai gerar um hash da string passada por parâmetro. Desta maneira você guarda apenas este hash e não expõe as senhas dos seus usuários. Para executar esse seed, execute o comando:

Agora que temos um usuário na nossa base de dados, vamos criar uma tela de login e fazer o controle de acesso.

Autenticação

A primeira coisa que precisamos para autenticar usuários é criar as rotas para isso. Como já existe um HomeController na nossa aplicação, vamos usar ele para fazer o login e logout do usuário. Também vamos bloquear o acesso para usuários não autenticados ao nosso controller de artigos. O visitante vai ver os artigos diretamente na raiz.

A verificação de autenticação usa um filtro chamado auth. Esse filtro já existe no arquivo app/filters.php. Ele verifica se o usuário é visitante e encaminha o usuário para login. Como eu utilizei na rota o caminho entrar, temos que alterar o filtro também.

O próximo passo é implementar o HomeController. Neste controller teremos dois métodos para entrar na nossa aplicação – getEntrar e postEntrar – e um método para encerrar a sessão – getSair. Vamos ver como fica o código:

A parte mais importante aqui é o postEntrar. Para executar a autenticação propriamente dita usamos o seguinte método: Auth::attempt(). O primeiro parâmetro é um array com a credenciais do usuário – independentemente do nome que você der para o campo senha, ele deve ser passado como password sempre. O segundo parâmetro serve para indicar se devemos lembrar do usuário ou não para a próxima sessão.

Para finalizar, precisamos de uma view para a tela de login. Crie o arquivo app/views/home/entrar.blade.php e coloque o seguinte conteúdo:

Ao acessar o endereço http://<dominio>/entrar essa é a tela que você verá:

 

 

Laravel-Login

Se você acessar o endereço http://<dominio>/artigos sem uma sessão autenticada, você será redirecionado para a tela de login. A última alteração que precisamos é alterar nosso menu para incluir o link para o login (quando o usuário não está autenticado) e para o logout. Abra o arquivo menu.blade.php e acrescente esse código no final da DIV #bs-example-navbar-collapse-1 (com ID = bs-example-navbar-collapse-1).

Bonus – Cadastro de Usuários

Como já falamos sobre como inserir dados no banco, não vou explicar como criar um cadastro para os usuários. Mas a implementação já está feita e disponível no Github. Para baixar o aplicativo clique aqui.

A parte importante é a segurança do nosso cadastro de usuários. Não queremos que ninguém além dos administradores acesse o cadastro de usuários. Para isso vamos acrescentar um novo grupo de rotas dentro da nossa verificação de autenticação:

Neste novo grupo usamos um filtro chamado auth.admin. Ele será responsável por validar se o usuário logado é admin ou não.

Conclusão

O controle de acesso no Laravel é bem simples de ser implementado. O framework já possui diversas funcionalidades para acelerar a construção do controle de usuários no sistema. Eu fiz diversas alterações aqui apenas para mostrar que são possíveis. Mas eu recomendo que você siga o padrão o máximo possível – utilizando o model User, o nome da tabela users e o campo password na sua tabela. Isso minimiza as customizações e reduz o trabalho.

Com este artigo finalizamos todos os itens mais genéricos do Laravel. A partir de agora vou começar uma sequencia de artigos mais menores e mais específicos. No próximo vou escrever um pouco mais sobre o Eloquent, dessa vez vou focar no relacionamento entre tabelas.

Este post é parte da série Desenvolvendo com Laravel.

33 respostas para “Usuários e Controle de Acesso no Laravel”

  1. Olá Oscar Dias,

    Muito boa sua série de tutoriais, me ajudou bastante, espero que continue postando. 🙂

    Tenho uma dúvida, quando eu for hospedar minha aplicação desenvolvida no Laravel em um servidor tipo hostgator, locaweb, etc, como faço para que a pasta public seja a referência, ou seja, tudo comece por ela?

    Outra pergunta, preciso de desenvolver um sistema grande, você recomenda que eu utilize o Laravel?

    Além da documentação oficial, onde mais você recomenda eu estudar?

    Um abraço amigo.

    1. Olá Carlos,

      Obrigado por acompanhar. As vezes eu não consigo escrever com a frequência que gostaria, mas ainda tem muito assunto para escrever, então vou continuar sim.

      Para hospedar em um servidor compartilhado eu recomendo que você crie uma pasta fora do www para colocar o Laravel e copie o conteúdo da pasta public dentro do www. Ficaria assim:
      /laravel

      • /app
      • /bootstrap
      • /vendor

      /www

      • /packages
      • .htaccess
      • index.php

      Depois você precisa atualizar o arquivo bootstrap/paths.php:

      // Modifique isso
      'public' => __DIR__.'/../public',

      // Para isso
      'public' => __DIR__.'/../../www',

      Depois precisa também editar o www/index.php:

      // Modificar
      require __DIR__.'/../bootstrap/autoload.php';
      $app = require_once __DIR__.'/../bootstrap/start.php';

      // Para
      require __DIR__.'/../laravel/bootstrap/autoload.php';
      $app = require_once __DIR__.'/../laravel/bootstrap/start.php';

      Isso deve ser o suficiente.

      Com relação ao uso do Laravel para desenvolver um sistema grande, eu acho uma boa sim. Principalmente pela qualidade do código que se obtém usando o Laravel. Facilita a manutenção no futuro e diminui algumas horas de trabalho. Se você está muito preocupado com a performance, pode usar um framework mais leve, como o CodeIgniter. Mas no final das contas o que vai pesar mais é o acesso ao banco de dados e tanto no Laravel como no CodeIgniter você pode criar queries bem complexas usando todos os joins necessários para otimizar a consulta.

      Para aprender mais tem um livro em http://daylerees.com/codebright que você pode acessar pelo site ou comprar o PDF (tem em PT-BR se preferir) que é bem interessante. Ele te apresenta o básico para começar e depois, quando você encontrar algum problema específico, recomendo o Google mesmo 😉

      Abraço

      1. interessante esse método , achei que do meu jeito seria mais fácil, mas por não ter conhecimento no frameword não rolou …
        tentei configurar o .htaccess da raiz e da pasta public conforme esse exemplo:

        https://www.reddit.com/r/laravel/comments/3mvs01/problem_with_notfoundhttpexception/

        só que não funcionou 🙁
        continuo com o erro : NotFoundHttpException in RouteCollection.php line 161:

        se você tiver uma outra dica … fico no aguardo.

        1. Boa tarde Roberto,

          Não sei se entendi sua dúvida. Pelo link que você mandou o problema era que o /public aparecia na URL. É este seu problema? Caso seja, não precisa mudar o .htaccess, mas sim o endereço para onde o apache ou o nginx está apontando – deve ser para a pasta public. Isso é diferente de outros frameworks, como o CodeIgniter por exemplo.

          Outra coisa, esse meu artigo é bem antigo, então sempre valida na documentação oficial do Laravel.

          Abraço

  2. Notei que para o usuarios e reminders, é usado o email como campo chave, mas se criar uma aplicação onde o campo chave não seja esse, e sim o username, como fazer?

    1. Para os usuários você pode substituir ou acrescentar um campo usuário sem problema. Recomendo usar um índice único para não repetir o campo. É claro que para enviar o reminder é necessário um e-mail.

  3. Muito legal seu tutorial, sou meio “Burro”rsss e fiz de boa sem problemas e sem erros, deu para entender bem.

    Estou fazendo a parte de inclusão dos usuários porem me deparei com um problema meio besta, a parte de senha e a lista Tipo(Autor e Admim) fiz assim:

    Senha
    {{ Form::password(‘senha’, ”, array(‘class’ => ‘form-control’, ‘placeholder’ => ‘Senha’)) }}

    Tipo
    {{ Form::select(‘size’, array(‘L’ => ‘Admin’, ‘S’ => ‘Autor’), ‘S’); }}

    Porem perde a formatação do CSS, você poderia me dizer como arrumar isso?

    Muito obrigado e parabéns pelo tutorial.
    Abimael

    1. Tudo bem, que bom que você está curtindo.
      Com relação a senha, não tem o segundo parâmetro, pois a senha nunca é enviada para a view, então fica assim:
      {{ Form::password(‘senha’, array(‘class’ => ‘form-control’, ‘placeholder’ => ‘Senha’)) }}

      No tipo de usuário, faltou definir a classe. Deve ser desta maneira:
      {{ Form::select(‘size’, array(‘L’ => ‘Admin’, ‘S’ => ‘Autor’), ‘S’, array(‘class’ => ‘form-control’)) }}

      Neste último select você pode passar no terceiro parâmetro $registro->size para buscar o valor do banco.

      Abraço

        1. O terceiro parâmetro da função Form::select() é a opção que vai aparecer marcada na tela. No exemplo você usou o campo “size”, por isso usei o mesmo campo. Se este campo for do usuário você pode usar:
          {{ Form::select(‘size’, array(‘L’ => ‘Admin’, ‘S’ => ‘Autor’), $usuario->size, array(‘class’ => ‘form-control’)) }}

          No meu exemplo era o tipo do usuário, portanto era assim:
          {{ Form::select(‘tipo’, array(‘admin’ => ‘Admin’, ‘autor’ => ‘Autor’), $usuario->tipo, array(‘class’ => ‘form-control’)) }}

          Percebe que eu usei o nome do select igual ao nome do campo da tabela: select name=”tipo” e $usuario->tipo.

          1. Cara muiiiito obrigado!

            Ja tentei aprender, Zend, CakePHP, Codeigniter entre outros que dei uma fuçada… Estas ferramentas não me deram aquele “Tcham” como deu o Laravel, não só por que ele é fácil de se aprender, mas também por que as outras ferramentas não apresentam um tutorial bacana como o seu, espero que estes tutorias continuem. Valeu mesmo!

            Abraços,
            Abimael

  4. Obrigado pelo tutorial, aprendi bastante coisas – considerando que sou leigo.

    No caso, baixei a versão 1.5 – quando fui testar ao inserir o artigo – resultou em mensagem de erro: ErrorException – Creating default object from empty value

    na parte:

    public function postEditar()
    {
    $artigo = Artigo::find(Input::get(‘id’));

    $artigo->titulo = Input::get(‘titulo’);
    $artigo->conteudo = Input::get(‘conteudo’);

    O q poderia ter acontecido?

    1. Tudo bem Leandro… Estranho este erro. Quando você acessa a página de edição do artigo e verifica o código fonte, há uma linha como a de baixo?



      Este input será usado para buscar o artigo no post. Se ele não encontrar um post, vai retornar false e não será possível acessar o objeto, retornando o erro que você encontrou…

    2. Comigo também aconteceu este erro, mas só ouve um pequeno “erro” no script de inserir que está direcionando para editar, mas é para inserir.


      {{ Form::open(array('url' => 'artigos/inserir', 'class' => 'form-horizontal', 'role' => 'form')) }}

      Por isso o erro, pois não é enviado nenhum ID.

  5. Muito boa a sua iniciativa. Comecei a estudar o Laravel, mas estava com dificuldades para achar material bom e explicativo. Achei. Quando pretende escrever mais sobre o assunto. Obrigado.

  6. Oscar, muito bom seu tutorial! Aprendi muito e criei gosto em trabalhar com o Laravel!
    Eu comecei a estudar na semana em que saiu o Laravel 5, mas fiz questão de estudar seu tutorial pra pegar uma base do framework, e pelo que eu já vi da versão 5, vai me ajudar bastante!
    Parabéns e muito obrigado por compartilhar seu conhecimento cara!

    Abraço!

  7. Primeiramente parabéns pelo artigo ficou muito bom e simples, agora tenho uma duvida vamos ver se consegue me ajudar.
    Eu gostaria de poder controlar permissões dentro das views, ou seja, pode ocultar alguns botoes que o usuário não tem permissão, como na sua opinião seria a melhor pratica para isso?

    Desde já agradeço a atenção.

    1. Rafael, existem várias maneiras de fazer isso. Se as permissões no seu aplicativo forem fixas, pode fazer algo como:

      @if(\Auth::user()->perfil == 'admin')
      ...
      @endif

      Caso você precise de permissões dinâmicas, onde o próprio usuário vai poder definir quem acessa cada componente, você vai precisar fazer isso através de banco de dados. Você pode criar uma tabela perfis (id, nome), outra funcionalidades (id, nome, url – essa lista de funcionalidade você pode criar uma classe e colocar hardcoded no código para simplificar) e outra acessos (id, perfil_id, funcionalidade_id, acesso (sim/não)) e um método no User model verificando se o usuário possui acesso a URL desejada. Nesse caso dinâmico tudo vai depender de como você organiza seu código… talvez a URL não seja o melhor caminho para controlar isso.

      E sempre lembra de verificar a permissão no controller ou rota. Mesmo que você esconda um botão não quer dizer que o usuário não vai acessar o link simplesmente mudando a URL no browser.

  8. Gostaria de agradecer pelo artigo, está me ajudando muito, mas ficaram algumas dúvidas, estou usando uma tabela de usuários onde os campos tem um padrão de nomenclatura diferente, por exemplo: usu_id, usu_nome, usu_email, etc.
    Seguindo os passos do artigo, montei o formulário de login e configurei para os nomes corretos do meu banco de dados, mas quando vou efetuar o login ele apresenta a mensagem “E-mail ou senha inválidos”.
    Tem mais alguma classe que preciso alterar os nomes dos campos, ou tem alguma forma de visualizar o sql que ele está enviando ao banco?

    1. O principal é o campo ID. É necessário declarar uma propriedade $primaryKey, assim como fizemos com o $table.


      protected $primaryKey = 'usu_id';

      Para ver as queries executadas você pode fazer o seguinte:

      DB::enableQueryLog(); // Isso só precisa no Laravel 5
      $queries = DB::getQueryLog();
      dd($queries); // ou print_r($queries)

      1. Obrigado pela dica, agora deu certo, mas surgiu outras dúvidas, pesquisei na internet sobre como mapear os campos que vem do banco, por exemplo, no banco tenho os campos usu_id, usu_nome, usu_email, … na aplicação eu gostaria de usar no formato Usuario->id, Usuario->nome, … Vi em um site em inglês a propriedade protected $maps = [], que aparentemente faria isso, mas não deu certo. Existe um meio de fazer essa conversão nos nomes dos campos automaticamente?

  9. Olá,

    Muito Bom o tutorial.
    Tenho uma dúvida. Não é preciso alterar em app/config/auth.php a tabela padrão de usuários também? Só alteramos o nome do Model :

    ‘model’ => ‘Usuario’,
    ‘table’ => ‘usuarios’,

    1. Boa tarde,

      Não é necessário. Como estamos usando ‘driver’ => ‘eloquent’, o que importa é a propriedade ‘model’. Se você trocar o driver para ‘database’, aí sim terá que atualizar a propriedade ‘table’.

      Abraço

  10. Cara, vc respondeu a pergunta dele e me ajudou a desvendar um mistério.. kkk
    Obrigado pelo tutorial.. espero que continue publicando sempre, muito bom!

    Abração ae!!!

  11. olá, parabéns pelo tutorial mais esta aparecendo esse erro

    [Symfony\Component\Debug\Exception\FatalThrowableError]
    Class ‘Usuario’ not found

    quando executo

    php artisan db:seed

    Sabe oq pode ser?

    Obrigado.

  12. olá, parabéns pelo tutorial..

    no meu arquivo auth.php não tem:

    |————————————————————————–
    | Authentication Model
    |————————————————————————–
    |
    | When using the “Eloquent” authentication driver, we need to know which
    | Eloquent model should be used to retrieve your users. Of course, it
    | is often just the “User” model but you may use whatever you like.
    |
    */

    ‘model’ => ‘Usuario’,

    Apenas:

    /*
    |————————————————————————–
    | User Providers
    |————————————————————————–
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user’s data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: “database”, “eloquent”
    |
    */

    ‘providers’ => [
    ‘users’ => [
    ‘driver’ => ‘eloquent’,
    ‘model’ => App\User::class,
    ],

    Esta aparecendo esse erro

    [Symfony\Component\Debug\Exception\FatalThrowableError]
    Class ‘Usuario’ not found

    quando executo

    php artisan db:seed

    Sabe oq pode ser?

    Obrigado.

    1. Qual versão do Laravel? A versão do tutorial era uma versão antiga (acho que 4.2). Você tem que tomar cuidado para o ‘model’ => App\User::class estar apontando para a classe correta.
      Por exemplo, se você renomeou o model para Usuario e moveu ele para dentro do diretório models, é interessante usar o namespace App\Models dentro do model. Nesse caso você precisaria trocar a configuração para ‘model’ => App\Models\Usuario::class.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *