Symfony 2自定义身份验证不使用正确的提供程序

时间:2012-07-08 03:00:28

标签: php symfony

我正在使用FOSRestBundle来创建REST API。对于身份验证,我使用的是一个标头,它随每个请求一起发送。它与this cookbook entry非常相似。

听众工作正常。一旦调用以下行,我就看不到任何调试或错误日志条目,它只会引发AuthenticationError异常:$returnValue = $this->authenticationManager->authenticate($token);

我怀疑被调用的提供者是main,而不是我添加的名为api的提供者。

security.yml 是唯一真正与食谱条目有很大偏差的配置文件:

security:
    encoders:
        Keobi\ModelBundle\Entity\User:
            algorithm: sha512
            iterations: 5000
            encode_as_base64: true

    role_hierarchy:
        ROLE_ADMIN:       [ROLE_USER, ROLE_ALLOWED_TO_SWITCH]
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    providers:
        main:
            entity: { class: KeobiModelBundle:User, property: email }
        api:
            entity: { class: KeobiModelBundle:Api, property: key }

    factories:
        - "%kernel.root_dir%/../src/Keobi/SecurityBundle/Resources/config/secrity_factories.yml"

    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        login:
            pattern:  ^/security/login$
            security: false

        api: # <- this is the firewall for my custom auth
            pattern: ^/api/
            #security: false
            api: true
            provider: api

        secured_area:
            pattern:    ^/(keobi|customer|security)/.*$
            form_login:
                check_path: /security/login_check
                login_path: /security/login
                success_handler: keobi_security.handler.authentication
                failure_handler: keobi_security.handler.authentication
                default_target_path: /
                target_path_parameter: _target_path
            logout:
                path:   /security/logout
                target: /security/login
                handlers: [keobi_security.handler.authentication]
            switch_user: { role: ROLE_ADMIN }

    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, roles: ROLE_ADMIN }

这是我的 ApiListener.php 文件:

<?php
namespace Keobi\SecurityBundle\Listener;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Keobi\SecurityBundle\Token\ApiToken;
use Symfony\Bridge\Monolog\Logger;

class ApiListener implements ListenerInterface
{
  protected $securityContext;
  protected $authenticationManager;
  protected $logger;
  protected $kernel;

  const AUTH_HEADER = 'x-keobi-authenticate';
  const AUTH_PATTERN = '/^Key="(?P<key>\w{40})", Hash="(?P<hash>\w+)", Created="(?P<created>\d+)"$/';
  const SIGN_HEADER = 'x-keobi-signature';

  public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, Logger $logger, \AppKernel $kernel)
  {
    $this->securityContext = $securityContext;
    $this->authenticationManager = $authenticationManager;
    $this->logger = $logger;
    $this->kernel = $kernel;
  }

  public function handle(GetResponseEvent $event)
  {
    $request = $event->getRequest();
    $kernel = $event->getKernel();

    if ($this->kernel->isDebug() && $request->query->has('_apikey') && $request->query->has('_apisecret') && $request->query->has('_ipaddress'))
    {
      $this->logger->debug('Debug key and secret used.');
      $token = new ApiToken();

      $created = time();
      $hash = hash('sha256', $request->query->get('_apikey') . $request->query->get('_apisecret') . strval($created));

      $token->key = $request->query->get('_apikey');
      $token->created = $created;
      $token->hash = $hash;
      $token->ipaddress = $request->query->get('_ipaddress');
    }
    elseif ($request->headers->has(self::AUTH_HEADER))
    {
      if (preg_match(self::AUTH_PATTERN, $request->headers->get(self::AUTH_HEADER), $matches))
      {
        $token = new ApiToken();

        $token->key = $matches['key'];
        $token->created = $matches['created'];
        $token->hash = $matches['hash'];
        $token->ipaddress = $request->getClientIp();
      }
    }

    if (isset($token))
    {
      $this->logger->debug($request->headers->get(self::AUTH_HEADER));

      try
      {
        $this->logger->debug(get_class($this->authenticationManager));
        $returnValue = $this->authenticationManager->authenticate($token);

        if ($returnValue instanceof TokenInterface)
          return $this->securityContext->setToken($returnValue);
        elseif ($returnValue instanceof Response)
          return $event->setResponse($returnValue);
      }
      catch (AuthenticationException $e)
      {
        $this->logger->err('Server failed to authenticate');
      }
    }

    # could not authenticate
    $response = new Response();
    $response->setStatusCode(403);
    $response->setContent('Could not be authenticated.');
    $event->setResponse($response);
  }
}

由于我发布了监听器并且监听器正在生成日志条目,因此这些是尝试身份验证时发生的日志条目:

2012-07-07 21:47:17 [2fiespfh-4b5a19dd] app.DEBUG: Key="0123456789012345678901234567890123456789", Hash="05707425769f01a82e2eee0b85018feeb6b96579f376f4632782b6b61c83b1fe", Created="1341655731"
2012-07-07 21:47:17 [2fiespfh-4b5a19dd] app.DEBUG: Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager
2012-07-07 21:47:17 [2fiespfh-4b5a19dd] app.ERROR: Server failed to authenticate

1 个答案:

答案 0 :(得分:1)

看起来这是 ENTIRELY 我的错。抛出ProviderNotFoundException的原因是因为supports中的ApiProvider方法正在检查错误的类。