问题
我希望通过访问令牌对用户进行身份验证,该令牌作为GET参数提供给第一个请求。
我从未在Symfony中实现过这样的东西,所以我遵循了How to Create a custom Authentication Provider中概述的步骤,但它"不起作用"。不触发AuthenticationProviderInterface
的authenticate
方法。
我尝试过的
因为它主要是大量的配置,我甚至不知道如何调试它。到目前为止,我得出的结论是:只有AccessTokenProvider
被构造,没有其他东西。
代码
这些是系统的相关部分:
安全性.yml
security:
# Snip default (empty) in_memory provider
firewalls:
# Snip dev and main (symfony default)
accesstoken_secured:
pattern: ^/admin/
accesstoken: true
服务.yml
services:
accesstoken.security.authentication.provider:
class: AppBundle'Security'Authentication'Provider'AccessTokenProvider
arguments:
- '' # User Provider
- '%kernel.cache_dir%/security/nonces'
public: false
accesstoken.security.authentication.listener:
class: AppBundle'Security'Firewall'AccessTokenListener
arguments: ['@security.token_storage', '@security.authentication.manager']
public: false
AccessTokenFactory
class AccessTokenFactory implements SecurityFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$providerId = 'security.authentication.provider.accesstoken.'.$id;
$container
->setDefinition($providerId, new DefinitionDecorator('accesstoken.security.authentication.provider'))
->replaceArgument(0, new Reference($userProvider))
;
$listenerId = 'security.authentication.listener.accesstoken.'.$id;
$container->setDefinition($listenerId, new DefinitionDecorator('accesstoken.security.authentication.listener'));
return array($providerId, $listenerId, $defaultEntryPoint);
}
public function getPosition()
{
return 'pre_auth';
}
public function getKey()
{
return 'accesstoken';
}
public function addConfiguration(NodeDefinition $node)
{
}
}
AccessTokenProvider
class AccessTokenProvider implements AuthenticationProviderInterface
{
private $userProvider;
public function __construct(UserProviderInterface $userProvider)
{
$this->userProvider = $userProvider;
}
public function authenticate(TokenInterface $token)
{
$user = $this->userProvider->loadUserByAccessToken($token->getAttribute('token'));
if ($this->isTokenValid($token)) {
$authenticatedToken = new AccessToken(['role_user']);
$authenticatedToken->setUser($user);
return $authenticatedToken;
}
throw new AuthenticationException('The WSSE authentication failed.');
}
protected function isTokenValid(AccessToken $token)
{
//TODO: Implement
return (bool)$token->token;
}
public function supports(TokenInterface $token)
{
return $token instanceof AccessToken;
}
}
AccessTokenListener
class AccessTokenListener
{
protected $tokenStorage;
protected $authenticationManager;
/**
* AccessTokenListener constructor.
* @param TokenStorageInterface $tokenStorage
* @param AuthenticationManagerInterface $authenticationManager
*/
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager)
{
$this->tokenStorage = $tokenStorage;
$this->authenticationManager = $authenticationManager;
}
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
$accesstoken = $request->get('accesstoken');
$token = new AccessToken();
$token->token = $accesstoken;
try {
$authToken = $this->authenticationManager->authenticate($token);
$this->tokenStorage->setToken($authToken);
return;
} catch (AuthenticationException $failed) {
// ... you might log something here
}
// By default deny authorization
$response = new Response();
$response->setStatusCode(Response::HTTP_FORBIDDEN);
$event->setResponse($response);
}
}
AccessToken
class AccessToken extends AbstractToken
{
public $token;
/**
* AccessToken constructor.
* @param array $roles
*/
public function __construct(array $roles = array())
{
parent::__construct($roles);
// If the user has roles, consider it authenticated
$this->setAuthenticated(count($roles) > 0);
}
/**
* Returns the user credentials.
*
* @return mixed The user credentials
*/
public function getCredentials()
{
return '';
}
}
我最终尝试用另一种方式实现它,使用教程How to Create a Custom Authentication System with Guard。
这使用了Symfony的新Guard
系统。它实际上非常容易设置!