Basic login functionality added.

This commit is contained in:
Alexey Skobkin 2018-06-25 04:02:27 +03:00
parent d953e8a319
commit ef29705a37
8 changed files with 139 additions and 21 deletions

View file

@ -1,7 +1,11 @@
security: security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers: providers:
in_memory: { memory: ~ } app_db_provider:
entity:
class: App\Entity\User
property: username
manager_name: default
encoders: encoders:
App\Entity\User: App\Entity\User:
algorithm: 'argon2i' algorithm: 'argon2i'
@ -12,19 +16,29 @@ security:
dev: dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/ pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false security: false
main: api:
pattern: ^/api/
anonymous: true anonymous: true
main:
pattern: ^/
anonymous: ~
provider: app_db_provider
form_login:
login_path: user_login
check_path: user_login
logout:
path: user_logout
target: /
remember_me:
secret: '%kernel.secret%'
lifetime: 604800
path: /
always_remember_me: true
# activate different ways to authenticate
# http_basic: true
# https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
# form_login: true
# https://symfony.com/doc/current/security/form_login_setup.html
# 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: ^/admin, roles: ROLE_ADMIN } - { path: ^/$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
# - { path: ^/profile, roles: ROLE_USER } - { path: /login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }

View file

@ -4,7 +4,7 @@ index:
controller: App\Controller\MainController::index controller: App\Controller\MainController::index
torrents_search: torrents_search:
path: /torrents/search path: /torrents
controller: App\Controller\TorrentController::searchTorrent controller: App\Controller\TorrentController::searchTorrent
requirements: requirements:
method: GET method: GET
@ -23,6 +23,13 @@ user_register:
method: GET method: GET
inviteCode: \w{32} inviteCode: \w{32}
user_login:
path: /login
controller: App\Controller\SecurityController::login
user_logout:
path: /logout
# API # API
api_v1_torrents: api_v1_torrents:
path: /api/v1/torrents path: /api/v1/torrents

View file

@ -2,16 +2,29 @@
namespace App\Controller; namespace App\Controller;
use App\Magnetico\Repository\TorrentRepository; use App\Form\LoginType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
class MainController extends Controller class MainController extends Controller
{ {
public function index(TorrentRepository $repo): Response public function index(): Response
{ {
return $this->render('index.html.twig', [ return $this->render('index.html.twig', [
'torrentsCount' => $repo->getTorrentsTotalCount(), 'loginForm' => $this->createLoginForm('')->createView(),
]); ]);
} }
private function createLoginForm(string $username): FormInterface
{
$form = $this->createForm(LoginType::class, null, [
'action' => $this->generateUrl('user_login'),
]);
$form->get('_username')->setData($username);
$form->add('submit', SubmitType::class);
return $form;
}
} }

View file

@ -0,0 +1,40 @@
<?php
namespace App\Controller;
use App\Form\LoginType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\{FormError, FormInterface};
use Symfony\Component\HttpFoundation\{Request, Response};
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\Translation\TranslatorInterface;
class SecurityController extends Controller
{
public function login(Request $request, AuthenticationUtils $authenticationUtils, TranslatorInterface $translator): Response
{
$lastError = $authenticationUtils->getLastAuthenticationError() ? $authenticationUtils->getLastAuthenticationError()->getMessage() : '';
$lastUsername = $authenticationUtils->getLastUsername();
$form = $this->createLoginForm($lastUsername);
$form->handleRequest($request);
if ($lastError) {
$form->addError(new FormError($lastError));
}
return $this->render('Security/login.html.twig', ['form' => $form->createView()]);
}
private function createLoginForm(string $username): FormInterface
{
$form = $this->createForm(LoginType::class, null, [
'action' => $this->generateUrl('user_login'),
]);
$form->get('_username')->setData($username);
$form->add('submit', SubmitType::class);
return $form;
}
}

26
src/Form/LoginType.php Normal file
View file

@ -0,0 +1,26 @@
<?php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\{PasswordType, TextType};
use Symfony\Component\Form\FormBuilderInterface;
class LoginType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('_username', TextType::class, ['mapped' => false])
->add('_password', PasswordType::class, ['mapped' => false])
;
}
public function getBlockPrefix()
{
// Empty prefix for default UsernamePasswordFrormAuthenticationListener
return '';
}
}

View file

@ -0,0 +1,7 @@
{% extends 'base.html.twig' %}
{% block content %}
<div id="form-login">
{{ form(form) }}
</div>
{% endblock %}

View file

@ -26,16 +26,25 @@
</button> </button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault"> <div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto"> {% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
<!--<li class="nav-item"> <ul class="navbar-nav mr-auto">
<a class="nav-link" href="#">Item</a> <li class="nav-item dropdown">
</li>--> <a href="#" class="nav-link dropdown-toggle" role="button" data-toggle="dropdown">
</ul> {{ app.user.username }}
</a>
<div class="dropdown-menu">
<a href="{{ path('user_logout') }}" class="dropdown-item">Logout</a>
</div>
</li>
</ul>
{% endif %}
{% if is_granted('ROLE_USER') %}
<form class="form-inline my-2 my-lg-0" action="{{ path('torrents_search') }}" method="get"> <form class="form-inline my-2 my-lg-0" action="{{ path('torrents_search') }}" method="get">
<input name="query" class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search" <input name="query" class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search"
value="{% if searchQuery is defined %}{{ searchQuery }}{% endif %}"> value="{% if searchQuery is defined %}{{ searchQuery }}{% endif %}">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form> </form>
{% endif %}
</div> </div>
</nav> </nav>

View file

@ -2,6 +2,8 @@
{% block content %} {% block content %}
<div class="well"> <div class="well">
<p>Torrents indexed: {{ torrentsCount }}</p> {% if not is_granted('ROLE_USER') %}
<a href="{{ path('user_login') }}" class="btn btn-lg btn-primary">Login</a>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}