通过Web服务进行Symfony2自定义连接

时间:2015-04-15 08:30:48

标签: web-services security symfony authentication connection

我正在尝试创建一个自定义连接,我应该使用Web服务。所以我在securitycustom provider上阅读了这个教程。现在我正在尝试使用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'))未连接到工具栏。所以我想我忘记了......

我是否需要使用Listener,UserToken和Factory来做到这一点?

1 个答案:

答案 0 :(得分: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类中删除$ roles:

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']

最后,在你的app config中:

security:
    area_secured:
        pattern:    ^/
        web_service:  ~
        form_login:
            login_path:  /login
            check_path:  /login_check
            default_target_path: /test
        logout:
            path:   /logout
            target: /