added remember me feature #53 (#98)

cleanup event subscriber
This commit is contained in:
Kevin Papst
2018-01-17 19:55:26 +01:00
committed by GitHub
parent 7df21f3f5a
commit 9a161b8fd9
26 changed files with 193 additions and 116 deletions

View File

@@ -30,6 +30,7 @@ use App\Repository\Query\ActivityQuery;
*
* @Route("/admin/activity")
* @Security("has_role('ROLE_ADMIN')")
* @Security("is_granted('IS_AUTHENTICATED_FULLY')")
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/

View File

@@ -28,6 +28,7 @@ use App\Repository\Query\CustomerQuery;
*
* @Route("/admin/customer")
* @Security("has_role('ROLE_ADMIN')")
* @Security("is_granted('IS_AUTHENTICATED_FULLY')")
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/

View File

@@ -29,6 +29,7 @@ use App\Repository\Query\ProjectQuery;
*
* @Route("/admin/project")
* @Security("has_role('ROLE_ADMIN')")
* @Security("is_granted('IS_AUTHENTICATED_FULLY')")
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/

View File

@@ -20,7 +20,6 @@ use App\Entity\Timesheet;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
use App\Form\TimesheetAdminForm;
/**
@@ -28,6 +27,7 @@ use App\Form\TimesheetAdminForm;
*
* @Route("/team/timesheet")
* @Security("has_role('ROLE_TEAMLEAD')")
* @Security("is_granted('IS_AUTHENTICATED_FULLY')")
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/
@@ -41,7 +41,6 @@ class TimesheetController extends AbstractController
* @Route("/", defaults={"page": 1}, name="admin_timesheet")
* @Route("/page/{page}", requirements={"page": "[1-9]\d*"}, name="admin_timesheet_paginated")
* @Method("GET")
* @Cache(smaxage="10")
*
* @param $page
* @param Request $request

View File

@@ -28,6 +28,7 @@ use Symfony\Component\HttpFoundation\Request;
*
* @Route("/admin/user")
* @Security("has_role('ROLE_SUPER_ADMIN')")
* @Security("is_granted('IS_AUTHENTICATED_FULLY')")
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/
@@ -61,7 +62,6 @@ class UserController extends AbstractController
* @Route("/", defaults={"page": 1}, name="admin_user")
* @Route("/page/{page}", requirements={"page": "[1-9]\d*"}, name="admin_user_paginated")
* @Method("GET")
* @Security("is_granted('view_all', user)")
*/
public function indexAction($page, Request $request)
{

View File

@@ -31,23 +31,16 @@ abstract class ConfigureMenuEvent extends Event
* @var SidebarMenuEvent
*/
private $event;
/**
* @var AuthorizationChecker
*/
private $auth;
/**
* ConfigureMenuEvent constructor.
* @param AuthorizationChecker $auth
* @param Request $request
* @param SidebarMenuEvent $event
*/
public function __construct(
AuthorizationChecker $auth,
Request $request,
SidebarMenuEvent $event
) {
$this->auth = $auth;
$this->request = $request;
$this->event = $event;
}
@@ -67,12 +60,4 @@ abstract class ConfigureMenuEvent extends Event
{
return $this->event;
}
/**
* @return AuthorizationChecker
*/
public function getAuth()
{
return $this->auth;
}
}

View File

@@ -9,42 +9,53 @@
* file that was distributed with this source code.
*/
namespace App\EventListener;
namespace App\EventSubscriber;
use App\Event\ConfigureMainMenuEvent;
use App\Event\ConfigureAdminMenuEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Avanzu\AdminThemeBundle\Model\MenuItemModel;
use Avanzu\AdminThemeBundle\Event\SidebarMenuEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
* Class MenuBuilder configures the main navigation.
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/
class MenuBuilder
class MenuBuilderSubscriber implements EventSubscriberInterface
{
/**
* @var EventDispatcherInterface
*/
private $eventDispatcher;
/**
* @var AuthorizationChecker
* @var AuthorizationCheckerInterface
*/
private $security;
/**
* MenuBuilder constructor.
* MenuBuilderSubscriber constructor.
* @param EventDispatcherInterface $dispatcher
* @param AuthorizationChecker $security
* @param AuthorizationCheckerInterface $security
*/
public function __construct(EventDispatcherInterface $dispatcher, AuthorizationChecker $security)
public function __construct(EventDispatcherInterface $dispatcher, AuthorizationCheckerInterface $security)
{
$this->eventDispatcher = $dispatcher;
$this->security = $security;
}
/**
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
'theme.sidebar_setup_menu' => ['onSetupNavbar', 100],
];
}
/**
* Generate the main menu.
*
@@ -53,9 +64,8 @@ class MenuBuilder
public function onSetupNavbar(SidebarMenuEvent $event)
{
$request = $event->getRequest();
$isLoggedIn = $this->security->isGranted('IS_AUTHENTICATED_FULLY');
$isLoggedIn = $this->security->isGranted('IS_AUTHENTICATED_REMEMBERED');
$isTeamlead = $isLoggedIn && $this->security->isGranted('ROLE_TEAMLEAD');
$isSuperAdmin = $isLoggedIn && $this->security->isGranted('ROLE_SUPER_ADMIN');
$event->addItem(
new MenuItemModel('dashboard', 'menu.homepage', 'dashboard', [], 'fa fa-dashboard')
@@ -64,7 +74,6 @@ class MenuBuilder
$this->eventDispatcher->dispatch(
ConfigureMainMenuEvent::CONFIGURE,
new ConfigureMainMenuEvent(
$this->security,
$request,
$event
)
@@ -74,16 +83,9 @@ class MenuBuilder
$admin = new MenuItemModel('admin', 'menu.admin', '', [], 'fa fa-wrench');
$event->addItem($admin);
if ($isSuperAdmin) {
$admin->addChild(
new MenuItemModel('user_admin', 'menu.admin_user', 'admin_user', [], 'fa fa-user')
);
}
$this->eventDispatcher->dispatch(
ConfigureAdminMenuEvent::CONFIGURE,
new ConfigureAdminMenuEvent(
$this->security,
$request,
$event
)

View File

@@ -9,29 +9,55 @@
* file that was distributed with this source code.
*/
namespace App\EventListener;
namespace App\EventSubscriber;
use App\Event\ConfigureMainMenuEvent;
use App\Event\ConfigureAdminMenuEvent;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Avanzu\AdminThemeBundle\Model\MenuItemModel;
use Avanzu\AdminThemeBundle\Event\SidebarMenuEvent;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
* Menus for timesheet
* Menu event subscriber for timesheet, customer, projects, activities.
* This is a sample implementation for developer who want to add new navigation entries in their bundles.
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/
class Menu
class MenuSubscriber implements EventSubscriberInterface
{
/**
* @var AuthorizationCheckerInterface
*/
private $security;
/**
* MenuSubscriber constructor.
* @param AuthorizationCheckerInterface $security
*/
public function __construct(AuthorizationCheckerInterface $security)
{
$this->security = $security;
}
/**
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
ConfigureMainMenuEvent::CONFIGURE => ['onMainMenuConfigure', 100],
ConfigureAdminMenuEvent::CONFIGURE => ['onAdminMenuConfigure', 100],
];
}
/**
* @param \App\Event\ConfigureMainMenuEvent $event
*/
public function onMainMenuConfigure(ConfigureMainMenuEvent $event)
{
$auth = $event->getAuth();
$auth = $this->security;
$isLoggedIn = $auth->isGranted('IS_AUTHENTICATED_FULLY');
$isLoggedIn = $auth->isGranted('IS_AUTHENTICATED_REMEMBERED');
$isUser = $isLoggedIn && $auth->isGranted('ROLE_USER');
if (!$isLoggedIn || !$isUser) {
@@ -50,13 +76,9 @@ class Menu
public function onAdminMenuConfigure(ConfigureAdminMenuEvent $event)
{
$menu = $event->getAdminMenu();
$auth = $event->getAuth();
$auth = $this->security;
if (!$auth->isGranted('IS_AUTHENTICATED_FULLY')) {
return;
}
if (!$auth->isGranted('ROLE_TEAMLEAD')) {
if (!$auth->isGranted('IS_AUTHENTICATED_REMEMBERED') || !$auth->isGranted('ROLE_TEAMLEAD')) {
return;
}
@@ -68,13 +90,18 @@ class Menu
return;
}
if ($auth->isGranted('ROLE_SUPER_ADMIN')) {
$menu->addChild(
new MenuItemModel('user_admin', 'menu.admin_user', 'admin_user', [], 'fa fa-user')
);
}
$menu->addChild(
new MenuItemModel('customer_admin', 'menu.admin_customer', 'admin_customer', [], 'fa fa-users')
)->addChild(
new MenuItemModel('project_admin', 'menu.admin_project', 'admin_project', [], 'fa fa-book')
)->addChild(
new MenuItemModel('activity_admin', 'menu.admin_activity', 'admin_activity', [], 'fa fa-tasks')
)
;
);
}
}

View File

@@ -9,19 +9,20 @@
* file that was distributed with this source code.
*/
namespace App\EventListener;
namespace App\EventSubscriber;
use App\Entity\User;
use Avanzu\AdminThemeBundle\Event\ShowUserEvent;
use Avanzu\AdminThemeBundle\Model\UserModel;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
/**
* Class NavbarShowUserListener
* Class NavbarShowUserSubscriber
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/
class NavbarShowUserListener
class NavbarShowUserSubscriber implements EventSubscriberInterface
{
/**
* @var TokenStorageInterface
@@ -37,6 +38,17 @@ class NavbarShowUserListener
$this->storage = $tokenStorage;
}
/**
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
'theme.navbar_user' => ['onShowUser', 100],
'theme.sidebar_user' => ['onShowUser', 100],
];
}
/**
* @param ShowUserEvent $event
*/

View File

@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace App\EventListener;
namespace App\EventSubscriber;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -23,7 +23,7 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
*
* @author Oleg Voronkovich <oleg-voronkovich@yandex.ru>
*/
class RedirectToPreferredLocaleListener
class RedirectToLocaleSubscriber
{
/**
* @var UrlGeneratorInterface

View File

@@ -36,6 +36,19 @@ abstract class AbstractVoter extends Voter
$this->decisionManager = $decisionManager;
}
/**
* @param TokenInterface $token
* @return bool
*/
protected function isFullyAuthenticated(TokenInterface $token)
{
if ($this->decisionManager->decide($token, ['IS_AUTHENTICATED_FULLY'])) {
return true;
}
return false;
}
/**
* @param string $role
* @param TokenInterface $token
@@ -43,7 +56,7 @@ abstract class AbstractVoter extends Voter
*/
protected function hasRole($role, TokenInterface $token)
{
if ($this->decisionManager->decide($token, array($role))) {
if ($this->decisionManager->decide($token, [$role])) {
return true;
}

View File

@@ -27,6 +27,12 @@ class ActivityVoter extends AbstractVoter
const EDIT = 'edit';
const DELETE = 'delete';
const ALLOWED_ATTRIBUTES = [
self::VIEW,
self::EDIT,
self::DELETE
];
/**
* @param string $attribute
* @param mixed $subject
@@ -34,7 +40,7 @@ class ActivityVoter extends AbstractVoter
*/
protected function supports($attribute, $subject)
{
if (!in_array($attribute, array(self::VIEW, self::EDIT, self::DELETE))) {
if (!in_array($attribute, self::ALLOWED_ATTRIBUTES)) {
return false;
}
@@ -107,6 +113,6 @@ class ActivityVoter extends AbstractVoter
*/
protected function canDelete(TokenInterface $token)
{
return $this->hasRole('ROLE_ADMIN', $token);
return $this->isFullyAuthenticated($token) && $this->hasRole('ROLE_ADMIN', $token);
}
}

View File

@@ -27,6 +27,12 @@ class CustomerVoter extends AbstractVoter
const EDIT = 'edit';
const DELETE = 'delete';
const ALLOWED_ATTRIBUTES = [
self::VIEW,
self::EDIT,
self::DELETE
];
/**
* @param string $attribute
* @param mixed $subject
@@ -34,7 +40,7 @@ class CustomerVoter extends AbstractVoter
*/
protected function supports($attribute, $subject)
{
if (!in_array($attribute, array(self::VIEW, self::EDIT, self::DELETE))) {
if (!in_array($attribute, self::ALLOWED_ATTRIBUTES)) {
return false;
}
@@ -107,6 +113,6 @@ class CustomerVoter extends AbstractVoter
*/
protected function canDelete(TokenInterface $token)
{
return $this->hasRole('ROLE_ADMIN', $token);
return $this->isFullyAuthenticated($token) && $this->hasRole('ROLE_ADMIN', $token);
}
}

View File

@@ -27,6 +27,12 @@ class ProjectVoter extends AbstractVoter
const EDIT = 'edit';
const DELETE = 'delete';
const ALLOWED_ATTRIBUTES = [
self::VIEW,
self::EDIT,
self::DELETE
];
/**
* @param string $attribute
* @param mixed $subject
@@ -34,7 +40,7 @@ class ProjectVoter extends AbstractVoter
*/
protected function supports($attribute, $subject)
{
if (!in_array($attribute, array(self::VIEW, self::EDIT, self::DELETE))) {
if (!in_array($attribute, self::ALLOWED_ATTRIBUTES)) {
return false;
}
@@ -107,6 +113,6 @@ class ProjectVoter extends AbstractVoter
*/
protected function canDelete(TokenInterface $token)
{
return $this->hasRole('ROLE_ADMIN', $token);
return $this->isFullyAuthenticated($token) && $this->hasRole('ROLE_ADMIN', $token);
}
}

View File

@@ -30,6 +30,14 @@ class TimesheetVoter extends AbstractVoter
const EDIT = 'edit';
const DELETE = 'delete';
const ALLOWED_ATTRIBUTES = [
self::START,
self::STOP,
self::VIEW,
self::EDIT,
self::DELETE
];
/**
* @param string $attribute
* @param mixed $subject
@@ -37,7 +45,7 @@ class TimesheetVoter extends AbstractVoter
*/
protected function supports($attribute, $subject)
{
if (!in_array($attribute, array(self::START, self::STOP, self::VIEW, self::EDIT, self::DELETE))) {
if (!in_array($attribute, self::ALLOWED_ATTRIBUTES)) {
return false;
}
@@ -146,6 +154,10 @@ class TimesheetVoter extends AbstractVoter
*/
protected function canDelete(Timesheet $timesheet, User $user, TokenInterface $token)
{
if (!$this->isFullyAuthenticated($token)) {
return false;
}
return $this->isOwnOrAdmin($timesheet, $user, $token);
}

View File

@@ -28,11 +28,9 @@ class UserVoter extends AbstractVoter
const PASSWORD = 'password';
const ROLES = 'roles';
const PREFERENCES = 'preferences';
const VIEW_ALL = 'view_all';
const ALLOWED_ATTRIBUTES = [
self::VIEW,
self::VIEW_ALL,
self::EDIT,
self::CREATE,
self::ROLES,
@@ -82,7 +80,6 @@ class UserVoter extends AbstractVoter
return $this->canEdit($subject, $user, $token);
case self::DELETE:
return $this->canDelete($subject, $user, $token);
case self::VIEW_ALL:
case self::CREATE: // create actually passes in the current user as $subject, not the new one
case self::ROLES:
return $this->canAdminUsers($token);
@@ -135,6 +132,6 @@ class UserVoter extends AbstractVoter
*/
protected function canAdminUsers(TokenInterface $token)
{
return $this->hasRole('ROLE_SUPER_ADMIN', $token);
return $this->isFullyAuthenticated($token) && $this->hasRole('ROLE_SUPER_ADMIN', $token);
}
}