我正在使用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
答案 0 :(得分:1)
看起来这是 ENTIRELY 我的错。抛出ProviderNotFoundException
的原因是因为supports
中的ApiProvider
方法正在检查错误的类。