我试图创造一个我应该使用Web服务的自定义连接。 所以,我阅读教程安全 ,这对一个自定义提供 。 现在,我想创建自己的登录表单有3个字段:电子邮件,密码和数字。 确认之后我才明白,我的/login_check
传递函数loadUserByUsername($username)
,但这个函数在参数只花了$username
,不把我的领域电子邮件和电话号码。 要执行我的web服务,我需要让我的3个ARGS。 我如何自定义登录表单?
我们的目标是:当用户提交登录表单我想与登录表单ARGS发送Web服务。 如果我没有错误我想连接我的用户通过web服务加载到Symfony2的工具栏我的反应一样,我想显示错误消息。
你可以在这里看到我的代码:
Security.yml:
security:
encoders:
MonApp\MonBundle\Security\User\WebserviceUser: sha512
#Symfony\Component\Security\Core\User\User: plaintext
# http://symfony.com/doc/current/book/security.html#hierarchical-roles
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
# http://symfony.com/doc/current/book/security.html#where-do-users-come- from-user-providers
providers:
#in_memory:
#memory:
#users:
#ryan: { password: ryanpass, roles: 'ROLE_USER' }
#admin: { password: kitten, roles: 'ROLE_ADMIN' }
webservice:
id: webservice_user_provider
# the main part of the security, where you can set up firewalls
# for specific sections of your app
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
area_secured:
pattern: ^/
anonymous: ~
form_login:
login_path: /login
check_path: /login_check
default_target_path: /test
logout:
path: /logout
target: /
# with these settings you can restrict or allow access for different parts
# of your application based on roles, ip, host or methods
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_AUTHENTICATED }
WebserviceUser.php:
<?php
namespace MonApp\MonBundle\Security\User;
use Symfony\Component\Security\Core\User\UserInterface;
class WebserviceUser implements UserInterface
{
private $email;
private $password;
private $num;
private $salt;
private $roles;
public function __construct($email, $password, $num, $salt, array $roles)
{
$this->email = $email;
$this->password = $password;
$this->num = $num;
$this->salt = $salt;
$this->roles = $roles;
}
public function getUsername()
{
return '';
}
public function getEmail()
{
return $this->email;
}
public function getPassword()
{
return $this->password;
}
public function getNum()
{
return $this->num;
}
public function getSalt()
{
return $this->salt;
}
public function getRoles()
{
return $this->roles;
}
public function eraseCredentials()
{}
public function isEqualTo(UserInterface $user)
{
if (!$user instanceof WebserviceUser) {
return false;
}
if ($this->email !== $user->getEmail()) {
return false;
}
if ($this->password !== $user->getPassword()) {
return false;
}
if ($this->num !== $user->getNum()) {
return false;
}
if ($this->getSalt() !== $user->getSalt()) {
return false;
}
return true;
}
}
WebserviceUserProvider.php
<?php
namespace MonApp\MonBundle\Security\User;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use MonApp\MonBundle\Security\User\WebserviceUser;
class WebserviceUserProvider implements UserProviderInterface
{
public function loadUserByUsername($username)
{
//print_r($username);
//die();
// effectuez un appel à votre service web ici
return new WebserviceUser('email', 'password', '45555', 'salt', array('ROLE_USER'));
//throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof WebserviceUser) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
print_r($user);
die();
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === 'MonApp\MonBundle\Security\User\WebserviceUser';
}
}
service.yml
parameters:
webservice_user_provider.class: MonApp\MonBundle\Security\User\WebserviceUserProvider
services:
webservice_user_provider:
class: "%webservice_user_provider.class%"
我不会把所有的代码,但是我的登录操作,模板和路由都完全不是安全链路都相同。 但是,我的用户new WebserviceUser('email', 'password', '45555', 'salt', array('ROLE_USER'))
没有连接到工具栏。 所以,我认为我忘了什么......
我需要用一个监听器,UserToken和工厂这样做呢?
好男孩,准备了很长的答案。
我假设你有一个文件夹命名为Security
放在/MonApp/MonBundle
首先,你需要一个自定义的令牌放置在Security/Token/WebServiceToken
<?php
namespace MonApp\MonBundle\Security\Token;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class WebServiceToken implements TokenInterface
{
protected $attributes;
protected $authenticated;
protected $user;
public function __construct($attributes)
{
$this->setAttributes($attributes);
$this->authenticated = false;
$this->user = null;
}
/**
* {@inheritdoc}
*/
public function serialize()
{
return serialize(
array(
is_object($this->user) ? clone $this->user : $this->user,
$this->authenticated,
$this->attributes
)
);
}
/**
* {@inheritdoc}
*/
public function unserialize($serialized)
{
list($this->user, $this->authenticated, $this->attributes) = unserialize($serialized);
}
public function __toString()
{
$result = '';
foreach($this->attributes as $name => $value)
{
$result .= "$name: $value ";
}
return "Token($result)";
}
/**
* Returns the user roles.
*
* @return RoleInterface[] An array of RoleInterface instances.
*/
public function getRoles()
{
return $this->user->getRoles();
}
public function getUser()
{
return $this->user;
}
public function setUser($user)
{
$this->user = $user;
}
public function getUsername()
{
return $this->user->getUsername();
}
public function isAuthenticated()
{
return $this->authenticated;
}
public function setAuthenticated($isAuthenticated)
{
$this->authenticated = $isAuthenticated;
}
public function eraseCredentials()
{
;
}
public function getAttributes()
{
return $this->attributes;
}
public function setAttributes(array $attributes)
{
$this->attributes = $attributes;
}
public function hasAttribute($name)
{
return array_key_exists($name, $this->attributes);
}
public function getAttribute($name)
{
if (!array_key_exists($name, $this->attributes)) {
throw new \InvalidArgumentException(sprintf('This token has no "%s" attribute.', $name));
}
return $this->attributes[$name];
}
public function setAttribute($name, $value)
{
$this->attributes[$name] = $value;
}
public function getCredentials()
{
return null;
}
}
然后,你需要在防火墙Security/Authentication/WebServiceAuthenticationListener
<?php
namespace MonApp\MonBundle\Security\Authentication;
use MonApp\MonBundle\Security\Token\WebServiceToken;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
class WebServiceAuthenticationListener implements ListenerInterface
{
protected $securityContext;
protected $authentificationManager;
protected $logger;
/**
* @param SecurityContextInterface $securityContext
* @param AuthenticationManagerInterface $authenticationManager
* @param LoggerInterface $logger
*/
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null)
{
$this->securityContext = $securityContext;
$this->authenticationManager = $authenticationManager;
$this->logger = $logger;
}
/**
* {@inheritdoc}
* @see \Symfony\Component\Security\Http\Firewall\ListenerInterface::handle()
*/
final public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
/**
* Fill $attributes with the data you want to set in the user
*/
$attributes = array();
$token = new WebServiceToken($attributes);
try {
if (null !== $this->logger ) {
$this->logger->debug(sprintf('Vérification du contexte de sécurité pour le token: %s', $token));
}
$token = $this->authenticationManager->authenticate($token);
if (null !== $this->logger) {
$this->logger->info(sprintf('Authentification réussie: %s', $token));
}
// Token authentifié
$this->securityContext->setToken($token);
}
catch (AuthenticationException $failed) {
throw $failed;
}
}
}
然后,你需要在身份验证提供Security/Authentication/WebServiceAuthenticationProvider
<?php
namespace MonApp\MonBundle\Security\Authentication;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use MonApp\MonBundle\Security\User\WebServiceUser;
use MonApp\MonBundle\Security\User\WebServiceUserProvider;
use MonApp\MonBundle\Security\Token\WebServiceToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
class WebServiceAuthenticationProvider implements AuthenticationProviderInterface
{
protected $provider;
public function __construct(WebServiceUserProvider $provider)
{
$this->provider = $provider;
}
public function authenticate(TokenInterface $token)
{
if (!$this->supports($token)) {
return new AuthenticationException('Token non supporté');
}
$user = $this->provider->createUser($token->getAttributes());
$token->setUser($user);
/**
* CALL TO THE WEB SERVICE HERE
*/
$myCallisASuccess = true;
if($myCallisASuccess) {
$token->setAuthenticated(true);
}
return $token;
}
public function supports(TokenInterface $token)
{
return $token instanceof WebServiceToken;
}
}
现在工厂...... Security/Factory/WebServiceFactory
<?php
namespace MonApp\MonBundle\Security\Factory;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
class WebServiceFactory implements SecurityFactoryInterface
{
/**
* {@inheritdoc}
* @see \Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface::create()
*/
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$providerId = 'security.authentication.provider.web_service'.$id;
$container->setDefinition($providerId, new DefinitionDecorator('web_service.security.authentication.provider'));
$listenerId = 'security.authentication.listener.web_service.'.$id;
$container->setDefinition($listenerId, new DefinitionDecorator('web_service.security.authentication.listener'));
return array($providerId, $listenerId, $defaultEntryPoint);
}
/**
* {@inheritdoc}
* @see \Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface::getPosition()
*/
public function getPosition()
{
return 'pre_auth';
}
/**
* {@inheritdoc}
* @see \Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface::getKey()
*/
public function getKey()
{
return 'web_service';
}
}
您可以通过添加此功能可以编辑WebServiceUserProvider
public function createUser(array $attributes)
{
$email = $attributes['email'];
$password = $attributes['password'];
$num = $attributes['num'];
$salt = $attributes['salt'];
$user = new WebServiceUser($email, $password, $num, $salt);
return $user;
}
而从你WebServiceUSer类中删除$角色:
public function __construct($email, $password, $num, $salt)
{
$this->email = $email;
$this->password = $password;
$this->num = $num;
$this->salt = $salt;
$this->roles = array();
}
好了,现在你已经做了所有你的安全等级。 让我们来配置此....
在类MonBundle
<?php
namespace MonApp\Bundle\MonBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use MonApp\Bundle\MonBundle\Security\Factory\WebServiceFactory;
class MonBundle extends Bundle
{
/**
* {@inheritdoc}
* @see \Symfony\Component\HttpKernel\Bundle\Bundle::build()
*/
public function build(ContainerBuilder $container)
{
parent::build($container);
// Ajout de la clef 'web_service' à l'extension security
$extension = $container->getExtension('security');
$extension->addSecurityListenerFactory(new WebServiceFactory());
}
}
在的配置MonBundle
services:
web_service.security.user.provider:
class: MonApp\Bundle\MonBundle\Security\User\WebServiceUserProvider
web_service.security.authentication.listener:
class: MonApp\Bundle\MonBundle\Security\Authentication\WebServiceAuthenticationListener
arguments: ['@security.context', '@web_service.security.authentication.provider','@?logger']
web_service.security.authentication.provider:
class: MonApp\Bundle\MonBundle\Security\Authentication\WebServiceAuthenticationProvider
arguments: ['@web_service.security.user.provider']
而在去年,在您的应用程序配置:
security:
area_secured:
pattern: ^/
web_service: ~
form_login:
login_path: /login
check_path: /login_check
default_target_path: /test
logout:
path: /logout
target: /