 
                    支付宝扫一扫付款
 
                    微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
Symfony标准认证过程中的一部分是取决于“user providers”。当用户提交用户名和密码时,认证层(authentication layer)会请求配置好的user provider返回给定用户名的user对象。Symfony接下来要检查用户的密码是否正确,并生成一个 security token,以便用户在当前会话期间能够保持认证过的身份。Symfony最牛之处,在于有四个user provider:in_memory,entity,ldap 和 chain。在本节,你将看到如何创建自己的user provider,如果你透过一个自定义的数据库、一个文件、或者 - 如本例所展示的 - 一个web service来访问用户的话,它将非常有用。
首先,无论你的user数据从 哪里 获取,你都需要创建一个 User 类来呈现那些数据。 User 可以是你希望的任何样子,并且能容纳任何数据。唯一的要求,是这个类必须实现 UserInterface 接口。此接口中的方法应该在自定义的user类中进行定义: getRoles(),
getPassword(),
getSalt(),
getUsername(),
eraseCredentials()。去实现 EquatableInterface 接口可能也是有用的,它定义了一个方法,用于检查user是否等同于当前用户。此接口需要一个 isEqualTo() 方法。
这就是你的 WebserviceUser 类实际看起来的样子:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | // src/AppBundle/Security/User/WebserviceUser.php
namespace AppBundle\Security\User;
 
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
 
class WebserviceUser implements UserInterface, EquatableInterface
{
    private $username;
    private $password;
    private $salt;
    private $roles;
 
    public function __construct($username, $password, $salt, array $roles)
    {
        $this->username = $username;
        $this->password = $password;
        $this->salt = $salt;
        $this->roles = $roles;
    }
 
    public function getRoles()
    {
        return $this->roles;
    }
 
    public function getPassword()
    {
        return $this->password;
    }
 
    public function getSalt()
    {
        return $this->salt;
    }
 
    public function getUsername()
    {
        return $this->username;
    }
 
    public function eraseCredentials()
    {
    }
 
    public function isEqualTo(UserInterface $user)
    {
        if (!$user instanceof WebserviceUser) {
            return false;
        }
 
        if ($this->password !== $user->getPassword()) {
            return false;
        }
 
        if ($this->salt !== $user->getSalt()) {
            return false;
        }
 
        if ($this->username !== $user->getUsername()) {
            return false;
        }
 
        return true;
    }
} | 
如果你有更多关于用户的信息 - 像是一个“first name” - 你可以添加一个 firstName 字段来持有该数据。
现在,你有了一个 User 类,你要创建一个user provider,它会从一些web service中获取用户信息,创建一个 WebserviceUser 对象,并对其填充数据。
user provider仅仅是一个实现了UserProviderInterface 接口的原生PHP类,它需要定义三个方法:loadUserByUsername($username), refreshUser(UserInterface $user) 和 supportsClass($class)。更多细节,参考 UserProviderInterface。
下例是它可能的样子:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // src/AppBundle/Security/User/WebserviceUserProvider.php
namespace AppBundle\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;
 
class WebserviceUserProvider implements UserProviderInterface
{
    public function loadUserByUsername($username)
    {
        // make a call to your webservice here
        // 在此调用你的webservice
        $userData = ...
        // pretend it returns an array on success, false if there is no user
        // 假设在成功时返回的是一个数组,没有用户时则返回false
 
        if ($userData) {
            $password = '...';
 
            // ...
 
            return new WebserviceUser($username, $password, $salt, $roles);
        }
 
        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))
            );
        }
 
        return $this->loadUserByUsername($user->getUsername());
    }
 
    public function supportsClass($class)
    {
        return $class === 'AppBundle\Security\User\WebserviceUser';
    }
} | 
现在把user provider设为服务:
| 1 2 3 4 | # app/config/services.yml
services:
    app.webservice_user_provider:
        class: AppBundle\Security\User\WebserviceUserProvider | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | <!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <services>
        <service id="app.webservice_user_provider"
            class="AppBundle\Security\User\WebserviceUserProvider"
        />
    </services>
</container> | 
| 1 2 3 4 5 6 7 | // app/config/services.php
use Symfony\Component\DependencyInjection\Definition;
 
$container->setDefinition(
    'app.webservice_user_provider',
    new Definition('AppBundle\Security\User\WebserviceUserProvider')
); | 
user provider的真正实现,可能还需要一些依赖或配置选项,以及其他服务。把所有这些当作参数传入服务定义中。
所有内容在你的security配置信息中汇集。把user provider添加到“security”根键下的的providers列表中。并且为这个user provider选择一个名称(如 “webservice”),把你刚才定义的服务标记为 id 键的值。
| 1 2 3 4 5 6 7 | # app/config/security.yml
security:
    # ...
    providers:
        webservice:
            id: app.webservice_user_provider | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <!-- app/config/security.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<srv:container xmlns="http://symfony.com/schema/dic/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:srv="http://symfony.com/schema/dic/services"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <config>
        <!-- ... -->
 
        <provider name="webservice" id="app.webservice_user_provider" />
    </config>
</srv:container> | 
Symfony还必须知道如何去加密网站用户们所提供的密码,如,在登录表单中填写的密码。你可以在security配置中添加一行“encoders”键:
| 1 2 3 4 5 6 | # app/config/security.yml
security:
    # ...
    encoders:
        AppBundle\Security\User\WebserviceUser: bcrypt | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <!-- app/config/security.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<srv:container xmlns="http://symfony.com/schema/dic/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:srv="http://symfony.com/schema/dic/services"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <config>
        <!-- ... -->
 
        <encoder class="AppBundle\Security\User\WebserviceUser"
            algorithm="bcrypt" />
    </config>
</srv:container> | 
当创建用户时(不管这些用户是如何创建的),不管密码是如何被加密的,此处的键值必须与该加密方式相对应。当用户提交其密码时,密码使用该算法加密,加密结果会和 getPassword() 方法所返回的“密码的hash值” 比对。
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。