Introdução
A autenticação é uma funcionalidade essencial em qualquer sistema, principalmente sistemas web. Ela não só garante o acesso e a guarda de informações pessoais, como ela garante que somente aqueles que tenham autorização consigam aceder às áreas protegidas da aplicação. Promove segurança e privacidade.
Requisitos
Neste artigo vou explorar como instalar a autenticação em uma aplicação Laravel, utilizando o Laravel Fortify. Como base, vou utilizar uma instalação do Laravel com Inertia e Vue. Caso queira saber mais sobre a aplicação base, consulte o artigo Laravel com Inertia e Vue.
Este artigo também assume que as rotas estejam configuradas através do pacote Ziggy, para uso da função route() no Vue. Caso a sua aplicação não tenha as rotas configuradas, consulte o artigo Utilizar rotas do Laravel no Vue.
Por fim, a sua aplicação poderá ter as views de autenticação que quiser. Se quiser também criar as views, acompanhe as views criadas no final deste artigo. Elas usa a framework Bootstrap CSS.
Quais são os requisitos de um autenticação?
Para se implementar uma autenticação, devemos pensar em:
- Se o utilizador anónimo poderá ou não se registar na aplicação.
- De que forma o utilizador poderá se autenticar e como validamos a sua identidade.
- O utilizador poderá ter esquecido a sua password, e neste caso deverá poder recuperá-la de forma segura.
Essas são algumas das considerações que temos que ter antes de iniciar.
Porque o Laravel Fortify?
O primeiro motivo da escolha do Laravel Fortify é que ele é um pacote oficial do Laravel que não impõe nenhuma interface (frontend). Enquanto existem pacotes “starter kits“, em Laravel, que já tem uma interface própria e vão além da autenticação, o Fortify faz todo o trabalho da autenticação sem se preocupar com o layout.
Principais Recursos do Fortify
- Registo de utilizadores: Fornece as rotas para criação de novas contas no site.
- Login e Logout: Faz a gestão da sessão do utilizador com segurança.
- Recuperação de passwords: Implementa solicitações e redefinições de password.
- Verificação de E-mail: Garante que o e-mail do utilizador seja autêntico.
- Autenticação de Dois Fatores (2FA): Adiciona uma camada extra de segurança.
- Atualização de Informações do Perfil: Permite aos utilizadores alterarem dados como password e e-mail.
- Confirmação de password: Protege ações sensíveis.
Instalação e configuração do Laravel Fortify
Sem mais delongas, vamos por a mão na massa.
Passo 1: Instale o Laravel Fortify através do composer:
composer require laravel/fortify
Passo 2: Publique o ficheiro de configuração:
php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"
Passo 3: Registe o Fortify nos Service Providers. Abra o ficheiro \bootstrap\providers.php
:
return [
// ...
App\Providers\FortifyServiceProvider::class,
];
Passo 4: Configure os serviços que estarão disponíveis em \config\fortify.php
. Os serviços que não serão utilizados pela sua aplicação, comente-os:
'features' => [
Features::registration(),
Features::resetPasswords(),
// Features::emailVerification(),
Features::updateProfileInformation(),
Features::updatePasswords(),
Features::twoFactorAuthentication([
'confirm' => true,
'confirmPassword' => true,
// 'window' => 0,
]),
],
Passo 5: Crie a ligação às views, onde está o frontend da sua aplicação, em app/Providers/FortifyServiceProvider.php
:
(...)
use Inertia\Inertia;
(...)
public function boot(): void
{
Fortify::createUsersUsing(CreateNewUser::class);
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
RateLimiter::for('login', function (Request $request) {
$throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())).'|'.$request->ip());
return Limit::perMinute(5)->by($throttleKey);
});
RateLimiter::for('two-factor', function (Request $request) {
return Limit::perMinute(5)->by($request->session()->get('login.id'));
});
Fortify::loginView(function () {
return Inertia::render('Auth/Login');
});
Fortify::registerView(function () {
return Inertia::render('Auth/Register');
});
Fortify::requestPasswordResetLinkView(function () {
return Inertia::render('Auth/ForgotPassword');
});
Fortify::resetPasswordView(function (Request $request) {
return Inertia::render('Auth/ResetPassword', [
'token' => $request->token,
'email' => $request->email,
]);
});
}
Se a sua aplicação já tiver as views de autenticação definidas, altere em conformidade o código acima, e a seguir pule o próximo passo. Caso não tenha, siga no próximo passo a criação das views.
Passo 6: Definir a rota principal
Com o Laravel Fortify é possível definir a rota para onde serão reencaminhados os utilizadores registados. No ficheiro \config\fortify.php
, configure a rota principal em:
/*
|--------------------------------------------------------------------------
| Home Path
|--------------------------------------------------------------------------
|
| Here you may configure the path where users will get redirected during
| authentication or password reset when the operations are successful
| and the user is authenticated. You are free to change this value.
|
*/
'home' => '/dashboard',
Passo 7: Informações do utilizador para o Vue
Para passar as informações do utilizador logado para o Vue, utiliza-se do Middleware do Inertia. Assim, altere o ficheiro \app\Http\Middleware\HandleInertiaRequests.php
:
public function share(Request $request): array
{
return array_merge(parent::share($request), [
// Share user data globally
'auth' => [
'user' => $request->user() ? [
'id' => $request->user()->id,
'name' => $request->user()->name,
'email' => $request->user()->email,
// Add any other user data you need
] : null,
],
'flash' => [
'success' => fn () => $request->session()->get('success'),
'warning' => fn () => $request->session()->get('warning'),
'info' => fn () => $request->session()->get('info'),
'error' => fn () => $request->session()->get('error'),
'place' => fn () => $request->session()->get('place'),
]
]);
}
Criação das views de Autenticação
Login
Crie o componente de Login, em resources/js/Pages/Auth/Login.vue
:
<script setup>
import { Link, useForm } from '@inertiajs/vue3'
const form = useForm({
email: '',
password: '',
remember: false,
})
const submit = () => {
form.post(route('login'))
}
</script>
<template>
<div class="d-flex flex-column min-vh-100 justify-content-center align-items-center bg-light">
<div class="container">
<div class="row justify-content-center">
<div class="col-12 col-sm-8 col-md-6 col-lg-4">
<div class="card shadow">
<div class="card-body">
<h1 class="h3 mb-4 text-center text-secondary">Login</h1>
<form @submit.prevent="submit">
<div class="mb-3">
<label class="form-label" for="email">
Email
</label>
<input
id="email"
type="email"
v-model="form.email"
class="form-control"
required
/>
<div v-if="form.errors.email" class="text-danger small mt-1">{{ form.errors.email }}</div>
</div>
<div class="mb-3">
<label class="form-label" for="password">
Senha
</label>
<input
id="password"
type="password"
v-model="form.password"
class="form-control"
required
/>
<div v-if="form.errors.password" class="text-danger small mt-1">{{ form.errors.password }}</div>
</div>
<div class="d-flex justify-content-between align-items-center mb-3">
<div class="form-check">
<input type="checkbox" v-model="form.remember" class="form-check-input" id="remember">
<label class="form-check-label small" for="remember">Lembrar-me</label>
</div>
<Link :href="route('password.request')" class="small text-primary text-decoration-none">
Esqueceu sua senha?
</Link>
</div>
<button
type="submit"
class="btn btn-primary w-100"
:disabled="form.processing"
>
{{ form.processing ? 'Entrando...' : 'Entrar' }}
</button>
</form>
<div class="text-center mt-4">
<Link :href="route('register')" class="small text-secondary text-decoration-none">
Não tem uma conta? Registe-se
</Link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
Registo
Crie o componente de Registo, em resources/js/Pages/Auth/Register.vue
:
<script setup>
import { Link, useForm } from '@inertiajs/vue3'
const form = useForm({
name: '',
email: '',
password: '',
password_confirmation: ''
})
const submit = () => {
form.post(route('register'))
}
</script>
<template>
<div class="d-flex flex-column min-vh-100 justify-content-center align-items-center bg-light">
<div class="container">
<div class="row justify-content-center">
<div class="col-12 col-sm-8 col-md-6 col-lg-4">
<div class="card shadow">
<div class="card-body">
<h1 class="h3 mb-4 text-center text-secondary">Registrar</h1>
<form @submit.prevent="submit">
<div class="mb-3">
<label class="form-label" for="name">
Nome
</label>
<input
id="name"
type="text"
v-model="form.name"
class="form-control"
required
/>
<div v-if="form.errors.name" class="text-danger small mt-1">{{ form.errors.name }}</div>
</div>
<div class="mb-3">
<label class="form-label" for="email">
Email
</label>
<input
id="email"
type="email"
v-model="form.email"
class="form-control"
required
/>
<div v-if="form.errors.email" class="text-danger small mt-1">{{ form.errors.email }}</div>
</div>
<div class="mb-3">
<label class="form-label" for="password">
Senha
</label>
<input
id="password"
type="password"
v-model="form.password"
class="form-control"
required
/>
<div v-if="form.errors.password" class="text-danger small mt-1">{{ form.errors.password }}</div>
</div>
<div class="mb-4">
<label class="form-label" for="password_confirmation">
Confirmar Senha
</label>
<input
id="password_confirmation"
type="password"
v-model="form.password_confirmation"
class="form-control"
required
/>
</div>
<button
type="submit"
class="btn btn-primary w-100"
:disabled="form.processing"
>
{{ form.processing ? 'Registrando...' : 'Registrar' }}
</button>
</form>
<div class="text-center mt-4">
<Link :href="route('login')" class="small text-secondary text-decoration-none">
Já tem uma conta? Faça login
</Link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
Proteja as rotas privadas
O middleware auth protege as rotas que exigem que o utilizador esteja autenticado. Altere o ficheiro \routes\web.php
para proteger as rotas:
// routes/web.php
use Inertia\Inertia;
(...)
Route::middleware(['auth:sanctum', 'verified'])->group(function () {
Route::get('/dashboard', function () {
return Inertia::render('Dashboard');
})->name('dashboard');
});
Espero que o artigo lhe seja útil. Qualquer questão, escreva nos comentários.