Skip to content

Use the new Security helper in some code examples #9847

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 7 additions & 15 deletions controller/argument_value_resolver.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,15 @@ retrieved from the token storage::
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Security;

class UserValueResolver implements ArgumentValueResolverInterface
{
private $tokenStorage;
private $security;

public function __construct(TokenStorageInterface $tokenStorage)
public function __construct(Security $security)
{
$this->tokenStorage = $tokenStorage;
$this->security = $security;
}

public function supports(Request $request, ArgumentMetadata $argument)
Expand All @@ -117,27 +116,20 @@ retrieved from the token storage::
return false;
}

$token = $this->tokenStorage->getToken();

if (!$token instanceof TokenInterface) {
return false;
}

return $token->getUser() instanceof User;
return $this->security->getUser() instanceof User;
}

public function resolve(Request $request, ArgumentMetadata $argument)
{
yield $this->tokenStorage->getToken()->getUser();
yield $this->security->getUser();
}
}

In order to get the actual ``User`` object in your argument, the given value
must fulfill the following requirements:

* An argument must be type-hinted as ``User`` in your action method signature;
* A security token must be present;
* The value must be an instance of the ``User``.
* The value must be an instance of the ``User`` class.

When all those requirements are met and ``true`` is returned, the
``ArgumentResolver`` calls ``resolve()`` with the same values as it called
Expand Down
37 changes: 19 additions & 18 deletions form/dynamic_form_modification.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ Using an event listener, your form might look like this::
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;

Expand All @@ -236,28 +235,30 @@ contains only this user's friends.
Luckily it is pretty easy to inject a service inside of the form. This can be
done in the constructor::

private $tokenStorage;
use Symfony\Component\Security\Core\Security;
// ...

private $security;

public function __construct(TokenStorageInterface $tokenStorage)
public function __construct(Security $security)
{
$this->tokenStorage = $tokenStorage;
$this->security = $security;
}

.. note::

You might wonder, now that you have access to the User (through the token
storage), why not just use it directly in ``buildForm()`` and omit the
event listener? This is because doing so in the ``buildForm()`` method
would result in the whole form type being modified and not just this
one form instance. This may not usually be a problem, but technically
a single form type could be used on a single request to create many forms
or fields.
You might wonder, now that you have access to the User, why not just use it
directly in ``buildForm()`` and omit the event listener? This is because
doing so in the ``buildForm()`` method would result in the whole form type
being modified and not just this one form instance. This may not usually be
a problem, but technically a single form type could be used on a single
request to create many forms or fields.

Customizing the Form Type
~~~~~~~~~~~~~~~~~~~~~~~~~

Now that you have all the basics in place you can take advantage of the ``TokenStorageInterface``
and fill in the listener logic::
Now that you have all the basics in place you can use the features of the
security helper to fill in the listener logic::

// src/AppBundle/Form/Type/FriendMessageFormType.php

Expand All @@ -266,16 +267,16 @@ and fill in the listener logic::
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Security;
// ...

class FriendMessageFormType extends AbstractType
{
private $tokenStorage;
private $security;

public function __construct(TokenStorageInterface $tokenStorage)
public function __construct(Security $security)
{
$this->tokenStorage = $tokenStorage;
$this->security = $security;
}

public function buildForm(FormBuilderInterface $builder, array $options)
Expand All @@ -286,7 +287,7 @@ and fill in the listener logic::
;

// grab the user, do a quick sanity check that one exists
$user = $this->tokenStorage->getToken()->getUser();
$user = $this->security->getUser();
if (!$user) {
throw new \LogicException(
'The FriendMessageFormType cannot be used without an authenticated user!'
Expand Down
10 changes: 5 additions & 5 deletions profiler/matchers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,22 @@ matcher::
// src/AppBundle/Profiler/SuperAdminMatcher.php
namespace AppBundle\Profiler;

use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\Security\Core\Security;

class SuperAdminMatcher implements RequestMatcherInterface
{
protected $authorizationChecker;
protected $security;

public function __construct(AuthorizationCheckerInterface $authorizationChecker)
public function __construct(Security $security)
{
$this->authorizationChecker = $authorizationChecker;
$this->security = $security;
}

public function matches(Request $request)
{
return $this->authorizationChecker->isGranted('ROLE_SUPER_ADMIN');
return $this->security->isGranted('ROLE_SUPER_ADMIN');
}
}

Expand Down
20 changes: 11 additions & 9 deletions security.rst
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ You can easily deny access from inside a controller::
// The second parameter is used to specify on what object the role is tested.
$this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');

// Old way :
// Old way:
// if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
// throw $this->createAccessDeniedException('Unable to access this page!');
// }
Expand Down Expand Up @@ -912,9 +912,7 @@ user is logged in (you don't care about roles), then you can use

public function helloAction($name)
{
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
throw $this->createAccessDeniedException();
}
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');

// ...
}
Expand Down Expand Up @@ -1042,6 +1040,8 @@ the User object, and use the ``isGranted()`` method (or
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
throw $this->createAccessDeniedException();
}
// equivalent shortcut:
// $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');

// boo :(. Never check for the User object to see if they're logged in
if ($this->getUser()) {
Expand All @@ -1052,16 +1052,18 @@ the User object, and use the ``isGranted()`` method (or

An alternative way to get the current user in a controller is to type-hint
the controller argument with
:class:`Symfony\\Component\\Security\\Core\\User\\UserInterface`
(and default it to ``null`` if being logged-in is optional)::
:class:`Symfony\\Component\\Security\\Core\\Security`::

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Security;

public function indexAction(UserInterface $user = null)
public function indexAction(Security $security)
{
// $user is null when not logged-in or anon.
$user = $security->getUser();
}

.. versionadded:: 3.4
The ``Security`` utility class was introduced in Symfony 3.4.

This is only recommended for experienced developers who don't extend from the
:ref:`Symfony base controller <the-base-controller-class-services>` and
don't use the :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerTrait`
Expand Down
28 changes: 21 additions & 7 deletions security/impersonating_user.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,29 @@ user rather than the impersonated user. Use the following snippet to iterate
over the user's roles until you find one that a ``SwitchUserRole`` object::

use Symfony\Component\Security\Core\Role\SwitchUserRole;
use Symfony\Component\Security\Core\Security;
// ...

$authorizationChecker = $this->get('security.authorization_checker');
$tokenStorage = $this->get('security.token_storage');
public class SomeService
{
private $security;

public function __construct(Security $security)
{
$this->security = $security;
}

public function someMethod()
{
// ...

if ($authorizationChecker->isGranted('ROLE_PREVIOUS_ADMIN')) {
foreach ($tokenStorage->getToken()->getRoles() as $role) {
if ($role instanceof SwitchUserRole) {
$impersonatorUser = $role->getSource()->getUser();
break;
if ($this->security->isGranted('ROLE_PREVIOUS_ADMIN')) {
foreach ($this->security->getToken()->getRoles() as $role) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like $this->security->getUser() shouldn't it hide ->getToken() to access to ->getRoles() directly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry but I don't understand this comment.

Copy link
Member

@yceruto yceruto May 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expected like $this->security->getUser() a shortcut like $this->security->getRoles() instead of $this->security->getToken()->getRoles() but I've seen that this has not been added to this helper. Nevermind, anyway this only documents what is implemented.

if ($role instanceof SwitchUserRole) {
$impersonatorUser = $role->getSource()->getUser();
break;
}
}
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions security/securing_services.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,27 @@ Before you add security, the class looks something like this::
}

Your goal is to check the user's role when the ``sendNewsletter()`` method is
called. The first step towards this is to inject the ``security.authorization_checker``
service into the object::
called. The first step towards this is to inject the ``security.helper`` service
using the :class:`Symfony\\Component\\Security\\Core\\Security` class::

// src/AppBundle/Newsletter/NewsletterManager.php

// ...
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Security;

class NewsletterManager
{
protected $authorizationChecker;
protected $security;

public function __construct(AuthorizationCheckerInterface $authorizationChecker)
public function __construct(Security $security)
{
$this->authorizationChecker = $authorizationChecker;
$this->security = $security;
}

public function sendNewsletter()
{
if (!$this->authorizationChecker->isGranted('ROLE_NEWSLETTER_ADMIN')) {
if (!$this->security->isGranted('ROLE_NEWSLETTER_ADMIN')) {
throw new AccessDeniedException();
}

Expand All @@ -72,8 +72,8 @@ service into the object::
}

If you're using the :ref:`default services.yml configuration <service-container-services-load-example>`,
Symfony will automatically pass the ``security.authorization_checker`` to your service
thanks to autowiring and the ``AuthorizationCheckerInterface`` type-hint.
Symfony will automatically pass the ``security.helper`` to your service
thanks to autowiring and the ``Security`` type-hint.

If the current user does not have the ``ROLE_NEWSLETTER_ADMIN``, they will
be prompted to log in.
Expand Down
14 changes: 5 additions & 9 deletions session/proxy_examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,15 @@ can intercept the session before it is written::

use AppBundle\Entity\User;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Security;

class ReadOnlySessionProxy extends SessionHandlerProxy
{
private $tokenStorage;
private $security;

public function __construct(\SessionHandlerInterface $handler, TokenStorageInterface $tokenStorage)
public function __construct(\SessionHandlerInterface $handler, Security $security)
{
$this->tokenStorage = $tokenStorage;
$this->security = $security;

parent::__construct($handler);
}
Expand All @@ -134,11 +134,7 @@ can intercept the session before it is written::

private function getUser()
{
if (!$token = $this->tokenStorage->getToken()) {
return;
}

$user = $token->getUser();
$user = $this->security->getUser();
if (is_object($user)) {
return $user;
}
Expand Down