2015-04-15 2 views
1

Я пытаюсь создать настраиваемое соединение, где я должен использовать веб-службу. Поэтому я прочитал учебник по адресу security и этот на custom provider. Теперь я пытаюсь создать свою собственную форму входа с тремя полями: адрес электронной почты, пароль и номер. После проверки я понял, что мой /login_check передает в функции loadUserByUsername($username), но эта функция приняла аргумент только $username и не берет поля и адрес электронной почты. Чтобы выполнить мой веб-сервис, мне нужно получить 3 аргумента. Как я могу настроить свою регистрационную форму?Пользовательское соединение Symfony2 через веб-службу

Цель: Когда пользователи отправляют форму для входа в систему, я хочу отправить веб-службу с помощью аргументов формы входа. Если я получу свой ответ без ошибок, я хочу подключить моего пользователя, загруженного веб-службой, к панели инструментов 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')) не подключен к панели инструментов. Поэтому я думаю, что я что-то забыл ...

Нужно ли мне использовать Listener, UserToken и Factory для этого?

+0

Вы используете брандмауэр Anonymous, возможно, вам должен создать класс «WebServiceFirewall» со ​​своей собственной фабрикой. – Med

+0

Спасибо, Med, у вас есть ссылка, где я могу реализовать собственный брандмауэр? Я положил 'anonymous: ~', потому что увидел это в поваренной книге, в руководстве по безопасности. – Remi

+0

Если вы все еще застряли в сообщении здесь, я помогу вам http://symfony.com/fr/doc/current/cookbook/security/custom_authentication_provider.html – Med

ответ

0

ОК мальчик, подготовьтесь к длинному ответу.

Я предполагаю, что у вас есть папка с именем 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:/
Смежные вопросы