Autenticação
O Nette fornece uma maneira de programar a autenticação em nossos sites, mas não nos força a nada. A implementação
depende inteiramente de nós. O Nette contém a interface Nette\Security\Authenticator
, que requer apenas um método
authenticate
, que verifica o usuário da maneira que quisermos.
Existem muitas opções de como um usuário pode ser autenticado. O método mais comum de autenticação é por senha (o usuário fornece seu nome ou e-mail e senha), mas existem outras formas. Você pode conhecer os botões do tipo “Login com Facebook” ou login com Google/Twitter/GitHub em alguns sites. Com o Nette, podemos ter qualquer método de login, ou podemos combiná-los. Depende apenas de nós.
Normalmente, escreveríamos nosso próprio autenticador, mas para este pequeno blog simples, usaremos o autenticador embutido,
que faz login com base em uma senha e nome de usuário armazenados no arquivo de configuração. É útil para fins de teste.
Portanto, adicionaremos a seguinte seção security
ao arquivo de configuração config/common.neon
:
security:
users:
admin: secret # usuário 'admin', senha 'secret'
O Nette criará automaticamente um serviço no contêiner DI.
Formulário de Login
Agora temos a autenticação pronta e precisamos preparar a interface do usuário para o login. Vamos criar um novo presenter
chamado SignPresenter
, que:
- exibirá o formulário de login (com nome de usuário e senha)
- após o envio do formulário, verificará o usuário
- fornecerá a opção de logout
Começaremos com o formulário de login. Já sabemos como os formulários funcionam nos presenters. Criaremos o presenter
SignPresenter
e escreveremos o método createComponentSignInForm
. Deve ficar algo assim:
<?php
namespace App\Presentation\Sign;
use Nette;
use Nette\Application\UI\Form;
final class SignPresenter extends Nette\Application\UI\Presenter
{
protected function createComponentSignInForm(): Form
{
$form = new Form;
$form->addText('username', 'Nome de usuário:')
->setRequired('Por favor, preencha seu nome de usuário.');
$form->addPassword('password', 'Senha:')
->setRequired('Por favor, preencha sua senha.');
$form->addSubmit('send', 'Entrar');
$form->onSuccess[] = $this->signInFormSucceeded(...);
return $form;
}
}
Existem campos para nome de usuário e senha.
Template
O formulário será renderizado no template in.latte
:
{block content}
<h1 n:block=title>Login</h1>
{control signInForm}
Callback de Login
Em seguida, adicionaremos o callback para o login do usuário, que será chamado logo após o envio bem-sucedido do formulário.
O callback apenas pega o nome de usuário e a senha que o usuário preencheu e os passa para o autenticador. Após o login, redirecionamos para a página inicial.
private function signInFormSucceeded(Form $form, \stdClass $data): void
{
try {
$this->getUser()->login($data->username, $data->password);
$this->redirect('Home:');
} catch (Nette\Security\AuthenticationException $e) {
$form->addError('Nome de usuário ou senha incorretos.');
}
}
O método User::login() lançará
uma exceção Nette\Security\AuthenticationException
se o nome de usuário e a senha não corresponderem aos dados
no arquivo de configuração. Como já sabemos, isso pode resultar em uma página de erro vermelha ou, no modo de produção, em
uma mensagem informando sobre um erro do servidor. No entanto, não queremos isso. Portanto, capturamos essa exceção no bloco
catch
e passamos uma mensagem de erro agradável e amigável para o formulário usando
$form->addError()
.
Assim que ocorrer um erro no formulário, a página com o formulário será redesenhada e uma mensagem agradável será exibida acima do formulário, informando ao usuário que ele preencheu o nome de usuário ou senha errados.
Protegendo Presenters
Protegeremos o formulário para adicionar e editar posts. Ele é definido no presenter EditPresenter
. O objetivo
é impedir o acesso à página por usuários que não estão logados.
Vytvoříme metodu startup()
, která se spouští ihned na začátku životního cyklu presenteru. Ta
přesměruje nepřihlášené uživatele na formulář s přihlášením.
public function startup(): void
{
parent::startup();
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Sign:in');
}
}
Ocultando Links
Um usuário não autorizado não pode mais ver as páginas create
ou edit
, mas ainda pode ver os
links para elas. Devemos escondê-los também. Um desses links está no template app/Presentation/Home/default.latte
e deve ser visível apenas para usuários logados.
Podemos escondê-lo usando um n:attribute chamado n:if
. Se esta condição for false
, toda a
tag <a>
, incluindo o conteúdo, permanecerá oculta.
<a n:href="Edit:create" n:if="$user->isLoggedIn()">Escrever nova postagem</a>
que é uma abreviação da seguinte notação (não confundir com tag-if
):
{if $user->isLoggedIn()}<a n:href="Edit:create">Escrever nova postagem</a>{/if}
Da mesma forma, ocultaremos também o link no template app/Presentation/Post/show.latte
.
Link de Login
Como realmente chegamos à página de login? Não há nenhum link que leve a ela. Então, vamos adicioná-lo ao template
@layout.latte
. Tente encontrar um local adequado – pode ser em quase qualquer lugar.
...
<ul class="navig">
<li><a n:href="Home:">Artigos</a></li>
{if $user->isLoggedIn()}
<li><a n:href="Sign:out">Sair</a></li>
{else}
<li><a n:href="Sign:in">Entrar</a></li>
{/if}
</ul>
...
Se o usuário não estiver logado, o link “Entrar” será exibido. Caso contrário, o link “Sair” será exibido.
A ação de logout (actionOut
) também foi adicionada ao SignPresenter
no código anterior.
Jelikož uživatele po odhlášení okamžitě přesměrujeme, není potřeba žádná šablona. Odhlášení vypadá takto:
public function actionOut(): void
{
$this->getUser()->logout();
$this->flashMessage('Logout realizado com sucesso.');
$this->redirect('Home:');
}
Apenas o método logout()
é chamado e, em seguida, uma mensagem agradável é exibida confirmando o logout
bem-sucedido usando flashMessage
.
Resumo
Temos um link para login e também para logout do usuário. Para autenticação, usamos o autenticador embutido e temos os dados de login no arquivo de configuração, pois se trata de uma aplicação de teste simples. Também protegemos os formulários de edição, para que apenas usuários logados possam adicionar e editar posts.
Aqui você pode ler mais sobre login de usuários e Autorização.