我在使用Symfony2的安全组件时遇到了麻烦。
首先,在身份验证过程中涉及多个对象:
如果我理解的话,安全工厂的目标是配置自定义身份验证。
监听器是身份验证的指挥。通过其attemptAuthentication
方法,它捕获表单提交(包含用户的凭据)并尝试对用户进行身份验证。在此方法中,监听器将创建AbstractToken
,然后将令牌传递给authenticate
的{{1}}方法。
之后,AuthenticationProvider
调用AuthenticationProvider
从Web服务或数据库等中检索用户数据......
UserProvider
完成其魔法后,会将一个User对象返回UserProvider
。
然后,AuthenticationProvider会创建一个新的令牌,该令牌由AuthenticationProvider
检索到的用户填充,然后将其重新调整为UserProvider
。
获得新令牌后,Listener
会做一些未知的魔法(我认为它会将令牌设置为安全上下文,但我不确定)。
在每个步骤中,我都做了一个用户对象的var_dump。除了“最后的步骤”之外,每个步骤都设置了角色:Listener
。
当Listener
从Listener
检索经过身份验证的令牌时,用户的角色为空。我无法弄清楚为什么......
UserProvider
class CompanyFactory implements SecurityFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$providerId = 'security.authentication.provider.company.'.$id;
$container
->setDefinition($providerId, new DefinitionDecorator('company.security.authentication.provider'))
->replaceArgument(0, new Reference($userProvider));
$listenerId = 'security.authentication.listener.company.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('company.security.authentication.listener'));
return array($providerId, $listenerId, $defaultEntryPoint);
}
public function getPosition()
{
return 'pre_auth';
}
public function getKey()
{
return 'company';
}
public function addConfiguration(NodeDefinition $node)
{
}
}
class CompanyListener extends AbstractAuthenticationListener
{
// Custructor stuff removed
protected function requiresAuthentication(Request $request)
{
if ($this->options['post_only'] && !$request->isMethod('post'))
{
return false;
}
return parent::requiresAuthentication($request);
}
protected function attemptAuthentication(Request $request)
{
$username = trim($request->get($this->options['username_parameter'], null, true));
$password = $request->get($this->options['password_parameter'], null, true);
$ip = $request->getClientIp();
$request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username);
$authToken = $this->authenticationManager->authenticate(new CompanyUserToken($username, $password, $ip));
return $authToken;
}
}
class CompanyProvider implements AuthenticationProviderInterface
{
private $userProvider;
public function __construct(UserProviderInterface $userProvider)
{
$this->userProvider = $userProvider;
}
public function authenticate(TokenInterface $token)
{
$user = $this->userProvider->loadUserByUsernamePassword($token->user, $token->getPassword(), $token->getIp());
$authenticatedToken = new CompanyUserToken($user->getUsername(), $user->getPassword(), $user->getIp(), $user->getRoles());
$authenticatedToken->setUser($user);
return $authenticatedToken;
}
public function supports(TokenInterface $token)
{
return $token instanceof CompanyUserToken;
}
}
class CompanyUserToken extends AbstractToken
{
private $password;
private $ip;
public function __construct($username, $password, $ip, array $roles = array())
{
parent::__construct($roles);
$this->password = $password;
$this->user = $username;
$this->ip = $ip;
// If the user has roles, consider it authenticated
$this->setAuthenticated(count($roles) > 0);
}
public function getCredentials()
{
return '';
}
public function getPassword()
{
return $this->password;
}
public function getIp()
{
return $this->ip;
}
}
class CompanyUserProvider implements UserProviderInterface
{
private $documentManager;
public function __construct($doctrineMongoDB)
{
$this->doctrineMongoDB = $doctrineMongoDB;
}
public function loadUserByUsername($username)
{
// Not used but needed by the interface
}
public function loadUserByUsernamePassword($username, $password, $ip)
{
// Does the magic, retrieve user datas from DB.
return $user;
}
public function refreshUser(UserInterface $user)
{
// Does nearly the same thing that the above method
return $refreshedUser;
}
public function supportsClass($class)
{
return $class === 'Company\UserBundle\Document\User';
}
}
parameters:
security.authentication.handler.class: Company\UserBundle\Security\Authentication\Handler\CompnayAuthenticationHandler
company_user_provider.class: Company\UserBundle\Security\User\CompanyUserProvider
services:
security.authentication.handler:
class: %security.authentication.handler.class%
public: false
arguments: [@router, @security.http_utils]
company.security.authentication.provider:
class: Company\UserBundle\Security\Authentication\Provider\CompanyProvider
arguments: [@company_user_provider]
company.security.authentication.listener:
class: Company\UserBundle\Security\Firewall\CompanyListener
arguments: [@security.context, @security.authentication.manager, @security.authentication.session_strategy, @security.http_utils, "company", @security.authentication.handler, @security.authentication.handler, {}, @logger, @event_dispatcher, @user.service.captcha]
company_user_provider:
class: %company_user_provider.class%
arguments: [@doctrine_mongodb]
user.service.captcha:
class: Company\UserBundle\Services\CaptchaService
arguments: [@form.factory]
以下是一些解释我问题的jms_security_extra:
secure_all_services: false
expressions: true
security:
encoders:
Company\UserBundle\Document\User: plaintext
role_hierarchy:
ROLE_VIP_USER: ROLE_USER
ROLE_ADMIN: [ROLE_USER, ROLE_VIP_USER]
providers:
webservice:
id: company_user_provider
firewalls:
company_secured:
pattern: ^/
company: true
anonymous: true
form_login:
login_path: login
check_path: login_check
post_only: true
use_referer: false
success_handler: security.authentication.handler
failure_handler: security.authentication.handler
logout:
path: /logout
target: login
access_control:
- { path: ^/admin, role: ROLE_ADMIN }
:
var_dumps
var_dump($user);
object(Company\UserBundle\Document\User)[142]
protected 'username' => string 'Supacoco' (length=13)
protected 'roles' =>
array (size=1)
0 => string 'ROLE_ADMIN' (length=10)
var_dump($authenticatedToken->getUser());
object(Company\UserBundle\Document\User)[142]
protected 'username' => string 'Supacoco' (length=13)
protected 'roles' =>
array (size=1)
0 => string 'ROLE_ADMIN' (length=10)
var_dump($authToken->getUser());
答案 0 :(得分:0)
经过深入挖掘后,我发现“AuthenticationProviderManager”在验证令牌后默认调用用户的方法“EraseCredentials”。
下面的代码解释了我的用户登录后失去其角色的原因。
public function eraseCredentials()
{
$this->roles = array();
}