composer require symnedi/security
Register the extension:
# app/config/config.neon
extensions:
- Symnedi\Security\DI\SecurityExtension
- Symnedi\EventDispatcher\DI\EventDispatcherExtension
First, read Symfony cookbook
Then create new voter implementing Symfony\Component\Security\Core\Authorization\Voter\VoterInterface
and register it as service in config.neon
:
services:
- App\SomeModule\Security\Voter\MyVoter
Then in place, where we need to validate access, we'll just use AuthorizationChecker
:
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class Presenter
{
/**
* @var AuthorizationCheckerInterface
*/
private $authorizationChecker;
public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
/**
* @param PresenterComponentReflection $element
*/
public function checkRequirements($element)
{
if ($this->authorizationChecker->isGranted('access', $element) === FALSE) {
throw new ForbiddenRequestException;
}
}
}
Original Symfony firewalls pretty simplified and with modular support by default.
All we need to create is a matcher and a listener.
This service will match all sites in admin module - urls starting with /admin
:
use Symfony\Component\HttpFoundation\Request;
use Symnedi\Security\Contract\HttpFoundation\RequestMatcherInterface;
class AdminRequestMatcher implements RequestMatcherInterface
{
/**
* {@inheritdoc}
*/
public function getFirewallName()
{
return 'adminSecurity';
}
/**
* {@inheritdoc}
*/
public function matches(Request $request)
{
$url = $request->getPathInfo();
return strpos($url, '/admin') === 0;
}
}
It will ensure that user is logged in and has 'admin' role, otherwise redirect.
use Nette\Application\AbortException;
use Nette\Application\Application;
use Nette\Application\Request;
use Nette\Security\User;
use Symnedi\Security\Contract\Http\FirewallListenerInterface;
class LoggedAdminFirewallListener implements FirewallListenerInterface
{
/**
* @var User
*/
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
/**
* {@inheritdoc}
*/
public function getFirewallName()
{
return 'adminSecurity';
}
/**
* {@inheritdoc}
*/
public function handle(Application $application, Request $applicationRequest)
{
if ( ! $this->user->isLoggedIn()) {
throw new AbortException;
}
if ( ! $this->user->isInRole('admin')) {
throw new AbortException;
}
}
}
Then we register both services.
services:
- AdminRequestMatcher
- LoggedAdminFirewallListener
That's it!
composer check-cs # see "scripts" section of composer.json for more details
vendor/bin/phpunit
Rules are simple:
- new feature needs tests
- all tests must pass
- 1 feature per PR
We would be happy to merge your feature then!