Merge branch 'feature/login' into develop
This commit is contained in:
commit
fab5249ac5
2
.env
2
.env
@ -37,5 +37,5 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
|||||||
###< symfony/messenger ###
|
###< symfony/messenger ###
|
||||||
|
|
||||||
###> symfony/mailer ###
|
###> symfony/mailer ###
|
||||||
# MAILER_DSN=null://null
|
MAILER_DSN=null://null
|
||||||
###< symfony/mailer ###
|
###< symfony/mailer ###
|
||||||
|
76
assets/styles/style.css
Normal file
76
assets/styles/style.css
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
body {
|
||||||
|
background: linear-gradient(to right, #5CE1E6, #C1FF72, #cb6ce6);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
font-family: "Fredoka", sans-serif;
|
||||||
|
font-optical-sizing: auto;
|
||||||
|
font-style: normal;
|
||||||
|
font-variation-settings: "wdth" 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 60%;
|
||||||
|
height: auto;
|
||||||
|
float: right;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: auto;
|
||||||
|
margin: auto 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-right: 20px;
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form div {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo{
|
||||||
|
margin-bottom: 65%;
|
||||||
|
margin-right: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-family: "Fredoka", sans-serif;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="password"] {
|
||||||
|
width: 90%;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #5CE1E6;
|
||||||
|
color: black;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #CB6CE6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit {
|
||||||
|
margin-left: 15%;
|
||||||
|
}
|
@ -9,6 +9,7 @@ security:
|
|||||||
entity:
|
entity:
|
||||||
class: App\Entity\Employee
|
class: App\Entity\Employee
|
||||||
property: email
|
property: email
|
||||||
|
# used to reload user from session & other features (e.g. switch_user)
|
||||||
firewalls:
|
firewalls:
|
||||||
dev:
|
dev:
|
||||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||||
@ -16,6 +17,19 @@ security:
|
|||||||
main:
|
main:
|
||||||
lazy: true
|
lazy: true
|
||||||
provider: app_user_provider
|
provider: app_user_provider
|
||||||
|
custom_authenticator: App\Security\LoginFormAuthenticator
|
||||||
|
logout:
|
||||||
|
path: app_logout
|
||||||
|
# where to redirect after logout
|
||||||
|
# target: app_any_route
|
||||||
|
|
||||||
|
remember_me:
|
||||||
|
secret: '%kernel.secret%'
|
||||||
|
lifetime: 604800
|
||||||
|
path: /
|
||||||
|
# by default, the feature is enabled by checking a checkbox in the
|
||||||
|
# login form, uncomment the following line to always enable it.
|
||||||
|
#always_remember_me: true
|
||||||
|
|
||||||
# activate different ways to authenticate
|
# activate different ways to authenticate
|
||||||
# https://symfony.com/doc/current/security.html#the-firewall
|
# https://symfony.com/doc/current/security.html#the-firewall
|
||||||
@ -26,7 +40,8 @@ security:
|
|||||||
# Easy way to control access for large sections of your site
|
# Easy way to control access for large sections of your site
|
||||||
# Note: Only the *first* access control that matches will be used
|
# Note: Only the *first* access control that matches will be used
|
||||||
access_control:
|
access_control:
|
||||||
#- { path: ^/*, roles: ROLE_USER }
|
- { path: ^/login, roles: PUBLIC_ACCESS }
|
||||||
|
- { path: ^/*, roles: IS_AUTHENTICATED_FULLY}
|
||||||
|
|
||||||
when@test:
|
when@test:
|
||||||
security:
|
security:
|
||||||
@ -35,7 +50,7 @@ when@test:
|
|||||||
# important to generate secure password hashes. In tests however, secure hashes
|
# important to generate secure password hashes. In tests however, secure hashes
|
||||||
# are not important, waste resources and increase test times. The following
|
# are not important, waste resources and increase test times. The following
|
||||||
# reduces the work factor to the lowest possible values.
|
# reduces the work factor to the lowest possible values.
|
||||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
Symfony\Component\Security\Core\Employee\PasswordAuthenticatedUserInterface:
|
||||||
algorithm: auto
|
algorithm: auto
|
||||||
cost: 4 # Lowest possible value for bcrypt
|
cost: 4 # Lowest possible value for bcrypt
|
||||||
time_cost: 3 # Lowest possible value for argon
|
time_cost: 3 # Lowest possible value for argon
|
||||||
|
49
migrations/Version20241017154551.php
Normal file
49
migrations/Version20241017154551.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241017154551 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SEQUENCE category_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE employee_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE incident_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE incident_type_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE mission_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE ride_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE skill_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE "user_id_seq" INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE TABLE "user" (id INT NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
|
$this->addSql('DROP SEQUENCE category_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE employee_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE incident_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE incident_type_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE mission_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE ride_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE skill_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE "user_id_seq" CASCADE');
|
||||||
|
$this->addSql('DROP TABLE "user"');
|
||||||
|
}
|
||||||
|
}
|
49
migrations/Version20241017154952.php
Normal file
49
migrations/Version20241017154952.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241017154952 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SEQUENCE category_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE employee_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE incident_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE incident_type_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE mission_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE ride_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE skill_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE "user_id_seq" INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE TABLE "user" (id INT NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, is_verified BOOLEAN NOT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
|
$this->addSql('DROP SEQUENCE category_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE employee_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE incident_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE incident_type_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE mission_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE ride_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE skill_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE "user_id_seq" CASCADE');
|
||||||
|
$this->addSql('DROP TABLE "user"');
|
||||||
|
}
|
||||||
|
}
|
49
migrations/Version20241114142616.php
Normal file
49
migrations/Version20241114142616.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241114142616 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SEQUENCE category_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE employee_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE incident_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE incident_type_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE mission_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE ride_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE skill_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE "user_id_seq" INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE TABLE "user" (id INT NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, is_verified BOOLEAN NOT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
|
$this->addSql('DROP SEQUENCE category_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE employee_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE incident_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE incident_type_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE mission_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE ride_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE skill_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE "user_id_seq" CASCADE');
|
||||||
|
$this->addSql('DROP TABLE "user"');
|
||||||
|
}
|
||||||
|
}
|
@ -5,15 +5,14 @@ namespace App\Controller;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||||
|
|
||||||
#[Route('/dashboard', name: 'DashboardController')]
|
|
||||||
class DashboardController extends AbstractController
|
class DashboardController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route('', name: '_index')]
|
#[Route(path: '/dashboard', name: 'dashboard')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
return $this->render('dashboard/index.html.twig');
|
return $this->render('dashboard/index.html.twig');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
|
@ -30,6 +30,11 @@ final class EmployeeController extends AbstractController
|
|||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
|
||||||
|
$employee->setPassword(
|
||||||
|
password_hash($form->get('plainPassword')->getData(), PASSWORD_BCRYPT)
|
||||||
|
);
|
||||||
|
|
||||||
$entityManager->persist($employee);
|
$entityManager->persist($employee);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
|
37
src/Controller/SecurityController.php
Normal file
37
src/Controller/SecurityController.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Form\LoginType;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||||
|
|
||||||
|
#[Route(path: '/login', name: 'security')]
|
||||||
|
class SecurityController extends AbstractController
|
||||||
|
{
|
||||||
|
#[Route(path: '', name: '_login')]
|
||||||
|
public function login(AuthenticationUtils $authenticationUtils): Response
|
||||||
|
{
|
||||||
|
// if ($this->getUser()) {
|
||||||
|
// return $this->redirectToRoute('dashboard');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get the login error if there is one
|
||||||
|
$error = $authenticationUtils->getLastAuthenticationError();
|
||||||
|
|
||||||
|
// last username entered by the user
|
||||||
|
$lastUsername = $authenticationUtils->getLastUsername();
|
||||||
|
|
||||||
|
|
||||||
|
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route(path: '/logout', name: '_logout')]
|
||||||
|
public function logout(): void
|
||||||
|
{
|
||||||
|
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,8 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
|||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints\Length;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
|
|
||||||
class EmployeeType extends AbstractType
|
class EmployeeType extends AbstractType
|
||||||
{
|
{
|
||||||
@ -19,7 +21,6 @@ class EmployeeType extends AbstractType
|
|||||||
->add('email', EmailType::class, ['label' => 'Email Address'])
|
->add('email', EmailType::class, ['label' => 'Email Address'])
|
||||||
->add('firstName', TextType::class, ['label' => 'First Name'])
|
->add('firstName', TextType::class, ['label' => 'First Name'])
|
||||||
->add('lastName', TextType::class, ['label' => 'Last Name'])
|
->add('lastName', TextType::class, ['label' => 'Last Name'])
|
||||||
->add('password', PasswordType::class, ['label' => 'Password'])
|
|
||||||
->add('roles', ChoiceType::class, [
|
->add('roles', ChoiceType::class, [
|
||||||
'label' => 'Roles (comma-separated)',
|
'label' => 'Roles (comma-separated)',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
@ -30,7 +31,23 @@ class EmployeeType extends AbstractType
|
|||||||
'multiple' => true, // Allow multiple selections
|
'multiple' => true, // Allow multiple selections
|
||||||
'expanded' => true, // Render as checkboxes
|
'expanded' => true, // Render as checkboxes
|
||||||
])
|
])
|
||||||
;
|
->add('plainPassword', PasswordType::class, [
|
||||||
|
// instead of being set onto the object directly,
|
||||||
|
// this is read and encoded in the controller
|
||||||
|
'mapped' => false,
|
||||||
|
'attr' => ['autocomplete' => 'new-password'],
|
||||||
|
'constraints' => [
|
||||||
|
new NotBlank([
|
||||||
|
'message' => 'Please enter a password',
|
||||||
|
]),
|
||||||
|
new Length([
|
||||||
|
'min' => 6,
|
||||||
|
'minMessage' => 'Your password should be at least {{ limit }} characters',
|
||||||
|
// max length allowed by Symfony for security reasons
|
||||||
|
'max' => 4096,
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
28
src/Form/LoginType.php
Normal file
28
src/Form/LoginType.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form;
|
||||||
|
use App\Entity\Employee;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||||
|
|
||||||
|
class LoginType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('email', EmailType::class)
|
||||||
|
->add('password', PasswordType::class)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => Employee::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
60
src/Security/LoginFormAuthenticator.php
Normal file
60
src/Security/LoginFormAuthenticator.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Security;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
|
||||||
|
use Symfony\Component\Security\Http\SecurityRequestAttributes;
|
||||||
|
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
||||||
|
|
||||||
|
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
|
||||||
|
{
|
||||||
|
use TargetPathTrait;
|
||||||
|
|
||||||
|
public const LOGIN_ROUTE = 'security_login';
|
||||||
|
|
||||||
|
public function __construct(private UrlGeneratorInterface $urlGenerator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authenticate(Request $request): Passport
|
||||||
|
{
|
||||||
|
$email = $request->getPayload()->getString('_username');
|
||||||
|
|
||||||
|
$request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $email);
|
||||||
|
|
||||||
|
return new Passport(
|
||||||
|
new UserBadge($email),
|
||||||
|
new PasswordCredentials($request->getPayload()->getString('_password')),
|
||||||
|
[
|
||||||
|
new CsrfTokenBadge('authenticate', $request->getPayload()->getString('_csrf_token')),
|
||||||
|
new RememberMeBadge(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||||
|
{
|
||||||
|
/*if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
|
||||||
|
return new RedirectResponse($targetPath);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// For example:
|
||||||
|
return new RedirectResponse($this->urlGenerator->generate('dashboard'));
|
||||||
|
//return new RedirectResponse($this->urlGenerator->generate('DashboardController'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getLoginUrl(Request $request): string
|
||||||
|
{
|
||||||
|
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
|
||||||
|
}
|
||||||
|
}
|
@ -288,6 +288,9 @@
|
|||||||
"config/packages/messenger.yaml"
|
"config/packages/messenger.yaml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfonycasts/verify-email-bundle": {
|
||||||
|
"version": "v1.17.0"
|
||||||
|
},
|
||||||
"twig/extra-bundle": {
|
"twig/extra-bundle": {
|
||||||
"version": "v3.13.0"
|
"version": "v3.13.0"
|
||||||
}
|
}
|
||||||
|
41
templates/security/login.html.twig
Normal file
41
templates/security/login.html.twig
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}HegreLand{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<form method="post">
|
||||||
|
{% if error %}
|
||||||
|
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if app.user %}
|
||||||
|
<div class="mb-3">
|
||||||
|
You are logged in as {{ app.user.userIdentifier }}, <a href="{{ path('security_logout') }}">Logout</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
|
||||||
|
<label for="username">Email</label>
|
||||||
|
<input type="email" value="{{ last_username }}" name="_username" id="username" class="form-control" autocomplete="email" required autofocus>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="password" name="_password" id="password" class="form-control" autocomplete="current-password" required>
|
||||||
|
|
||||||
|
<input type="hidden" name="_csrf_token"
|
||||||
|
value="{{ csrf_token('authenticate') }}"
|
||||||
|
>
|
||||||
|
|
||||||
|
{#
|
||||||
|
Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
|
||||||
|
See https://symfony.com/doc/current/security/remember_me.html
|
||||||
|
|
||||||
|
<div class="checkbox mb-3">
|
||||||
|
<input type="checkbox" name="_remember_me" id="_remember_me">
|
||||||
|
<label for="_remember_me">Remember me</label>
|
||||||
|
</div>
|
||||||
|
#}
|
||||||
|
|
||||||
|
<button class="btn btn-lg btn-primary" type="submit">
|
||||||
|
Sign in
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user