How to access the user Token in an injected servic

2019-02-25 00:51发布

I have the below code where I am trying to re-encode passwords as users log in (the database has bee migrated form a legacy website). However, I'm not sure what I'm doing wrong as I keep getting errors:

Attempted to call an undefined method named "forward" of class "AppBundle\Service\HubAuthenticator".

I have set things up as follows:

security.yml

security:
    encoders:
        AppBundle\Entity\Member:
            id: club.hub_authenticator

services.yml

services:
    //This should be central service than then calls the second
    club.hub_authenticator:
        class: AppBundle\Service\HubAuthenticator

    club.password_rehash:
        class: AppBundle\Service\PasswordRehash

Hubauthenticator.php

namespace AppBundle\Service;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;

class HubAuthenticator extends \Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder implements PasswordEncoderInterface
{
    function __construct($cost=13)
    {
        parent::__construct($cost);
    }

    function isPasswordValid($encoded, $raw, $salt)
    {
        // Test for legacy authentication (and conditionally rehash the password stored in the database if true)
        if ($this->comparePasswords($encoded, sha1("saltA".$raw."saltB"))) {
            $this->forward('club.password_rehash:rehash');
        }

        // Test for Symfony's Bcrypt authentication (any passwords just rehashed in previous step should work here)
        if (parent::isPasswordValid($cost=13, $encoded,$raw,$salt)) return true ;
    }
}

PasswordRehash.php

namespace AppBundle\Service;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;

class PasswordRehash extends \Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder
{
    // Customises BCryptPasswordEncoder class to use legacy SHA method
    function rehash($member, $raw, $salt)
    {
        //Salt is null as Symfony documentation says it is better to generate a new one
        parent::encodePassword($member->getPlainPassword, $salt=null ) ;
    }
}

Some other previous attempts for completeness:

My guess is that the problem is that I am misunderstanding what objects are available to me. My understanding is that the user hasn't been authenticated at this point so have tried and removed the below attempts:

Trying to inject the $member into the HubAuthenticator service:

function __construct($cost=13)
{
    parent::__construct($cost, \Member $member);
}

When trying to get the plainpassword to rehash:

$this->get('security.context')->getToken()->getUser()->getPlainPassword();

1条回答
够拽才男人
2楼-- · 2019-02-25 01:01

In your services, you can only access what dependencies you've injected.

So, to access the current user object, you need to pass it as argument:

service:

club.password_rehash:
    class: AppBundle\Service\PasswordRehash
    arguments: [ "@security.token_storage" ]

Constructor:

use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class HubAuthenticator extends \Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder implements PasswordEncoderInterface
{
    private $storage;

    function __construct($cost = 13, TokenStorageInterface $storage)
    {
        parent::__construct($cost);

        $this->storage = $storage;
        // Now you can use:
        // $user = $this->storage->getToken()->getUser();
    }
}

Then, to access the second service, same way, inject it.

Add it to the service arguments:

club.password_rehash:
    class: AppBundle\Service\PasswordRehash
    arguments: [ "@security.token_storage", "@club.password_rehash" ]

Add it to your constructor:

private $storage;
private $passwordRehash

function __construct($cost = 13, TokenStorageInterface $storage, PasswordRehash $passwordRehash)
{
    parent::__construct($cost);

    $this->storage = $storage;
    $this->passwordRehash = $passwordRehash;
    // Now you can use:
    // $this->passwordRehash->rehash(...);
}

Hope this helps you.

查看更多
登录 后发表回答