Olá pessoas,
Vamos ver como usar middlewares no Slim.
Middlewares são códigos que rodam antes e/ou depois do Slim manipular a requisição e resposta.
Aqui tem um pequeno gráfico mostrando os middlewares:
.
Para mais informações você pode dar uma olhada na documentação do Slim
Então nos vamos começar com o nosso template inicial:
Você pode ver o código aqui: https://github.com/GrupoToneladas/Blog-Slim-Middleware. (Para ter acesso ao código nesse estado use a tag “inicio” desse repositório git checkout inicio
).
Nós temos três actions, respondendo por três seções do sistema. Iremos criar middlewares para verificar se o usuário possui acesso a aquela seção.
Primeiramente, para deixar mais simples o post, vamos fazer um “login” fake. Inclua a seguinte classe na pasta app/src/Model
(a pasta não existe, por tanto, crie ela), com o nome UserLoginModel.php
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<?php
namespace App\Model;
class UserLoginModel
{
public function checkLogin($usuario, $senha)
{
if ($usuario == 'admin' && $senha == 'admin') {
$_SESSION = [
'logado' => true,
'acessos' => [
'admin',
'usuarios',
]
];
} elseif ($usuario == 'usuarios' && $senha == 'usuarios') {
$_SESSION = [
'logado' => true,
'acessos' => [
'usuarios'
]
];
}
return true;
}
}
|
via GIPHY
Perigo
Por favor,
NUNCA faça isso em um sistema em produção. Usuário e senha
DEVEM estar num banco de dados e com a senha criptografada (
password_hash e
password_verify estão aí pra isso).
O usuário “admin” tem acesso a todo sistema e o usuário “usuarios” tem acesso somente a seção de “/usuarios”. E se não estiver logado, terá acesso somente a “home”.
Primeiro vamos adicionar a sessão do PHP no Twig. Edite o arquivo de dependencia e adicione as linhas a seguir, antes do return da view:
1
2
|
$env = $view->getEnvironment();
$env->addGlobal('session', $_SESSION);
|
Ficando assim:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<?php
$container = $app->getContainer();
$container['view'] = function ($container) {
$settings = $container->get('settings')['view'];
$view = new \Slim\Views\Twig($settings['template_path'], [
'cache' => $settings['cache_path']
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
$env = $view->getEnvironment();
$env->addGlobal('session', $_SESSION);
return $view;
};
# Actions
$container[App\Action\HomeAction::class] = function ($container) {
return new App\Action\HomeAction($container->get('view'));
};
$container[App\Action\AdminAction::class] = function ($container) {
return new App\Action\AdminAction($container->get('view'));
};
$container[App\Action\UsuariosAction::class] = function ($container) {
return new App\Action\UsuariosAction($container->get('view'));
};
|
E adicione o inicio de sessão no arquivo public/index.php
:
Ficando assim:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php
session_start();
include __DIR__ . "/../vendor/autoload.php";
$settings = include __DIR__ . "/../app/config/settings.php";
$app = new \Slim\App($settings);
include __DIR__ . "/../app/config/dependencies.php";
include __DIR__ . "/../app/config/routes.php";
$app->run();
|
Vamos adicionar o formulário de login, a rota e o action que vai responder por esse formulário.
Adicione o seguinte trecho no arquivo app/templates/home.html
, logo após a tag de h1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
{% if session.logado == false %}
<div class="row" style="margin-top: 70px">
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-primary">
<div class="panel-heading">Acesso ao sistema</div>
<div class="panel-body">
<form class="form-horizontal" action="/logar" method="POST">
<div class="form-group">
<label class="control-label col-sm-2" for="usuario">Usuário</label>
<div class="col-sm-8"><input id="usuario" class="form-control" type="text" name="usuario" placeholder="Usuário"></div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="senha">Senha</label>
<div class="col-sm-8"><input id="senha" class="form-control" type="password" name="senha" placeholder="Senha"></div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-6"><input class="form-control btn btn-primary" type="submit" value="Entrar"></div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endif %}
|
Ficando assim:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
{% extends "base.html" %}
{% block content %}
<h1>Usando o Slim Middleware!</h1>
{% if session.logado == false %}
<div class="row" style="margin-top: 70px">
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-primary">
<div class="panel-heading">Acesso ao sistema</div>
<div class="panel-body">
<form class="form-horizontal" action="/logar" method="POST">
<div class="form-group">
<label class="control-label col-sm-2" for="usuario">Usuário</label>
<div class="col-sm-8"><input id="usuario" class="form-control" type="text" name="usuario" placeholder="Usuário"></div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="senha">Senha</label>
<div class="col-sm-8"><input id="senha" class="form-control" type="password" name="senha" placeholder="Senha"></div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-6"><input class="form-control btn btn-primary" type="submit" value="Entrar"></div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endif %}
{% endblock %}
|
Agora adicione a rota de “/logar”:
1
2
|
$app->post('/logar', App\Action\AcessoLogin::class)
->setName('acesso/logar');
|
E a rota de deslogar:
1
2
3
4
5
6
|
$app->get('/deslogar', function ($request, $response, $args) {
session_destroy();
return $response->withStatus(302)->withHeader('Location', '/');
});
|
Ficando assim:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?php
$app->get('/', App\Action\HomeAction::class)
->setName('home');
$app->get('/admin', App\Action\AdminAction::class)
->setName('admin');
$app->get('/usuarios', App\Action\UsuariosAction::class)
->setName('usuarios');
$app->post('/logar', App\Action\AcessoLoginAction::class)
->setName('acesso/logar');
$app->get('/deslogar', function ($request, $response, $args) {
session_destroy();
return $response->withStatus(302)->withHeader('Location', '/');
});
|
Adicione o Action de acesso na pasta app/src/Action
com o nome AcessoLogin.php
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<?php
namespace App\Action;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use App\Model\UserLoginModel;
class AcessoLoginAction
{
private $model;
public function __construct(UserLoginModel $model)
{
$this->model = $model;
}
public function __invoke(Request $request, Response $response, $args)
{
$dados = $request->getParsedBody();
$this->model->checkLogin($dados['usuario'], $dados['senha']);
return $response->withStatus(302)->withHeader('Location', '/');
}
}
|
Perceba que pegamos os dados vindo do formulário com o metodo getParsedBody
do $request e não passamos nenhuma mensagem se o login foi feito com sucesso ou não, somente mandados para a página inicial com os metodos withStatus
e withHeader
. Para passar essa mensagens use a biblioteca Slim/Flash, você pode ver um tutorial nosso aqui: Usando mensagens flash no Slim.
Agora vamos adicionar essa classe nas nossas dependencias:
1
2
3
|
$container[App\Action\AcessoLoginAction::class] = function ($container) {
return new App\Action\AcessoLoginAction($container->get('Model\UserLogin'));
};
|
Aproveitamos para adicionar o model nas dependencias também:
1
2
3
4
|
# Model
$container['Model\UserLogin'] = function ($container) {
return new App\Model\UserLoginModel();
};
|
Ficando assim:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<?php
$container = $app->getContainer();
$container['view'] = function ($container) {
$settings = $container->get('settings')['view'];
$view = new \Slim\Views\Twig($settings['template_path'], [
'cache' => $settings['cache_path']
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
return $view;
};
# Actions
$container[App\Action\HomeAction::class] = function ($container) {
return new App\Action\HomeAction($container->get('view'));
};
$container[App\Action\AdminAction::class] = function ($container) {
return new App\Action\AdminAction($container->get('view'));
};
$container[App\Action\UsuariosAction::class] = function ($container) {
return new App\Action\UsuariosAction($container->get('view'));
};
$container[App\Action\AcessoLoginAction::class] = function ($container) {
return new App\Action\AcessoLoginAction($container->get('Model\UserLogin'));
};
# Model
$container['Model\UserLogin'] = function ($container) {
return new App\Model\UserLoginModel();
};
|
Agora temos um sistema de login BEM rudimentar, vamos criar o middleware que vai verificar a sessão.
Adicione a seguinte pasta em app/src/Middleware/
.
Adicione o middleware Admin.php
, com o seguinte conteudo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?php
namespace App\Middleware;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
class Admin
{
public function __invoke(Request $request, Response $response, $next)
{
$response = $next($request, $response);
if (!isset($_SESSION['logado']) || !(in_array('admin', $_SESSION['acessos']))) {
$response = $response->withStatus(302)->withHeader('Location', '/');
}
return $response;
}
}
|
Adicione a classe nas dependencias:
1
2
3
4
|
#Middleware
$container[App\Middleware\Admin::class] = function () {
return new App\Middleware\Admin();
};
|
Ficando assim:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
<?php
$container = $app->getContainer();
$container['view'] = function ($container) {
$settings = $container->get('settings')['view'];
$view = new \Slim\Views\Twig($settings['template_path'], [
'cache' => $settings['cache_path']
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
$env = $view->getEnvironment();
$env->addGlobal('session', $_SESSION);
return $view;
};
# Actions
$container[App\Action\HomeAction::class] = function ($container) {
return new App\Action\HomeAction($container->get('view'));
};
$container[App\Action\AdminAction::class] = function ($container) {
return new App\Action\AdminAction($container->get('view'));
};
$container[App\Action\UsuariosAction::class] = function ($container) {
return new App\Action\UsuariosAction($container->get('view'));
};
$container[App\Action\AcessoLoginAction::class] = function ($container) {
return new App\Action\AcessoLoginAction($container->get('Model\UserLogin'));
};
# Model
$container['Model\UserLogin'] = function ($container) {
return new App\Model\UserLoginModel();
};
#Middleware
$container[App\Middleware\Admin::class] = function () {
return new App\Middleware\Admin();
};
|
E adicione nas rotas o middleware, para isso adicione o metodo add()
na rota que deseja ter o middleware:
1
2
3
|
$app->get('/admin', App\Action\AdminAction::class)
->setName('admin')
->add(App\Middleware\Admin::class);
|
Assim, onde estiver o middleware App\Middleware\Admin
somente quem tem login de admin pode acessar.
Deixo o desafio de adicionar o middleware de usuarios e fazer com que usuários com esse login acessem somente a seção de usuarios. A resposta está no nosso Github.
Até a próxima.