Symfony自定义身份验证提供程序 - 用户未完全登录(已登录,未经过身份验证)

时间:2015-04-21 23:20:51

标签: symfony authentication symfony-2.3

我正在创建一个自定义身份验证提供程序。我编写了自己的身份验证提供程序,监听程序,令牌和所有内容。它基于表单登录,我已经逐步完成了代码,所有内容似乎都配置正确。一切都按正确的顺序调用,我的身份验证提供程序被完美地调用。身份验证提供程序成功验证用户身份,并返回经过身份验证的令牌。我扩展 AbstractAuthenticationListener ,在 handle 方法中,它将设置安全上下文。

用户似乎已登录,但在调试工具栏中,未设置令牌,我看到“您未经过身份验证”和“无令牌”。

我是否缺少任何配置设置?为什么用户将登录,身份验证提供程序成功返回,使用经过身份验证的令牌,在安全上下文中设置但仍未进行身份验证?关于如何调试这个的任何提示?

(我会根据需要发布代码。)

编辑:令牌定义:

这很简单,只是从AbstractToken扩展而来:

class UserToken extends AbstractToken
{
    private $username;
    private $password;
    private $domain;
    private $providerKey;

    public function __construct($username, $password, $domain, $provider_key, array $roles = array('ROLE_USER'))
    {
        parent::__construct($roles);
        $this->username = $username;
        $this->password = $password;
        $this->domain = $domain;
        $this->providerKey = $provider_key;

    }

    public function getCredentials()
    {
        return '';
    }

    function getUsername() {
        return $this->username;
    }

    function getDomain() {
        return $this->domain;
    }
    function getPassword() {
        return $this->password;
    }

    function getProviderKey(){
        return $this->providerKey;
    }
}

身份验证侦听器:

class Listener extends AbstractAuthenticationListener
{
    protected $authenticationManager;

    public function __construct(
      SecurityContextInterface $securityContext,
      AuthenticationManagerInterface $authenticationManager,
      SessionAuthenticationStrategyInterface $sessionStrategy,
      HttpUtils $httpUtils,
      $providerKey,
      AuthenticationSuccessHandlerInterface $successHandler,
      AuthenticationFailureHandlerInterface $failureHandler,
      array $options = array(),
      LoggerInterface $logger = null,
      EventDispatcherInterface $dispatcher = null
      //CsrfProviderInterface $csrfProvider = null
    ) {

        parent::__construct(
          $securityContext,
          $authenticationManager,
          $sessionStrategy,
          $httpUtils,
          $providerKey,
          $successHandler,
          $failureHandler,
          array_merge(
            array(
              'username_parameter' => '_username',
              'password_parameter' => '_password',
              'domain_parameter' => '_domain',
              'csrf_parameter' => '_csrf_token',
              'intention' => 'authenticate',
              'post_only' => true,
            ),
            $options
          ),
          $logger,
          $dispatcher
        );

    }

    /**
     * Performs authentication.
     *
     * @param Request $request A Request instance
     *
     * @return TokenInterface|Response|null The authenticated token, null if full authentication is not possible, or a Response
     *
     * @throws AuthenticationException if the authentication fails
     */
    protected function attemptAuthentication(Request $request)
    {
        // Create initial unauthenticated token and pass data to the authentication manager.
        // TODO validate request data.
        $username = trim($request->request->get($this->options['username_parameter'], null, true));
        $password = $request->request->get($this->options['password_parameter'], null, true);
        $domain = $request->request->get($this->options['domain_parameter'], null, true);
        $token =  $this->authenticationManager->authenticate(new UserToken($username, $password, $domain, $this->providerKey));
        return $token;
    }
}

上面的代码将通过AuthenticationManager调用提供程序上的auth函数:

//This is from the AuthenticationProvider
public function authenticate(TokenInterface $token) {
    $loginHandler = new LoginAuthenticationHandler($token->getUsername(), $token->getPassword(), $token->getDomain());
 //This code just calls our web service and authenticates. I removed some business logic here, but this shows the gist of it.
    if(!$boAuthenticationToken = $loginHandler->authenticate())
    {
        throw new AuthenticationException('Bad credentials');
    }
    else{
        $user = $this->userProvider->loadUserByUsername($token->getUsername());
        //$user = $this->userProvider->getUser($token, $boAuthenticationToken);

        // Set the user which will be invoked in the controllers.
        $token->setUser($user);
        $token->setAuthenticated(true);
        return $token;
    }
}

Bundle Services.yml

parameters:

services:
    ws.security.authentication.provider:
      #http://blog.vandenbrand.org/2012/06/19/symfony2-authentication-provider-authenticate-against-webservice/
      class: Aurora\OurCustomBundle\Security\Authentication\Provider\Provider
      arguments: ["bo_remove_this_with_bo_auth_service", "", "@security.user_checker", "", "@security.encoder_factory"]

    ws.security.authentication.listener:
      class: Aurora\OurCustomBundle\Security\Firewall\Listener
      parent: security.authentication.listener.abstract
      abstract: true
      #arguments: []
      arguments: ["@security.context", "@security.authentication.manager", "@security.authentication.session_strategy", "@security.http_utils", "ws.user_provider", "@security.authentication.customized_success_handler", "@main.cas.rest.user.authentication.failure.service"]


    ws.user_provider:
      class: Aurora\OurCustomBundle\Security\User\UserProvider

最后,UserProvider

class UserProvider implements UserProviderInterface
{
    public function loadUserByUsername($username)
    {
        //Just return a simple user for now.
        return new User($username, array('ROLE_USER'));
    }

    public function refreshUser(UserInterface $user)
    {
        if (!$user instanceof User) {
            throw new UnsupportedUserException(
              sprintf('Instances of "%s" are not supported.', get_class($user))
            );
        }

        return $this->loadUserByUsername($user->getUsername());
    }

    public function supportsClass($class)
    {
        return $class === 'Aurora\OurCustomBundle\Security\User\User';
    }
}

1 个答案:

答案 0 :(得分:0)

经过几个小时的拔毛,我发现了问题!

令牌实现不正确。由于我实现了自己的Token,它从AbstractToken扩展而来,我还需要实现serialize()和unserialize()函数。

一旦我这样做,代码就可以了。更新后的Token类如下所示:

class UserToken extends AbstractToken
{
    private $username;
    private $password;
    private $domain;
    private $providerKey;

    public function __construct($username, $password, $domain, $provider_key, array $roles = array('ROLE_USER'))
    {
        parent::__construct($roles);
        $this->username = $username;
        $this->password = $password;
        $this->domain = $domain;
        $this->providerKey = $provider_key;

    }

    public function getCredentials()
    {
        return '';
    }

    function getUsername() {
        return $this->username;
    }

    function getDomain() {
        return $this->domain;
    }
    function getPassword() {
        return $this->password;
    }

    function getProviderKey(){
        return $this->providerKey;
    }

    function serialize(){
        return serialize(array($this->username, $this->password, $this->domain, parent::serialize()));
    }

    function unserialize($serialized){
        list($this->username, $this->password, $this->domain, $parentSerialization) = unserialize($serialized);
        parent::unserialize($parentSerialization);
    }
}
相关问题