> Symfony中文手册 > 如何使用多个User Providers

如何使用多个User Providers

超高难文档 Chain Provider虽非常用功能,但在需要的时候,配置和使用却极其方便。它从一个很小的侧面体现出Symfony的无比强大。

译注:本文描述的只是一种场合,堪用的场景还有很多。在实际操作时要特别注意不同的provider之间不能有任何潜在冲突,否则会报出难查之错。

每一种认证机制(如,Http认证,表单登录等)都要使用一个明确的user provider,默认时,它们将使用(配置文件中)第一个被声明的user provider。但如果你想“通过配置信息来指定少量用户,其余用户走数据库”时怎么办?这时就要通过创建一个新的provider将此二者“链”(chains)在一起。

1
2
3
4
5
6
7
8
9
10
11
12
# app/config/security.yml
security:
    providers:
        chain_provider:
            chain:
                providers: [in_memory, user_db]
        in_memory:
            memory:
                users:
                    foo: { password: test }
        user_db:
            entity: { class: AppBundle\Entity\User, property: username }
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
<!-- 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="chain_provider">
            <chain>
                <provider>in_memory</provider>
                <provider>user_db</provider>
            </chain>
        </provider>
 
        <provider name="in_memory">
            <memory>
                <user name="foo" password="test" />
            </memory>
        </provider>
 
        <provider name="user_db">
            <entity class="AppBundle\Entity\User" property="username" />
        </provider>
    </config>
</srv:container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// app/config/security.php
$container->loadFromExtension('security', array(
    'providers' => array(
        'chain_provider' => array(
            'chain' => array(
                'providers' => array('in_memory', 'user_db'),
            ),
        ),
        'in_memory' => array(
            'memory' => array(
               'users' => array(
                   'foo' => array('password' => 'test'),
               ),
            ),
        ),
        'user_db' => array(
            'entity' => array(
                'class' => 'AppBundle\Entity\User',
                'property' => 'username',
            ),
        ),
    ),
));

现在所有的认证机制将使用 chain_provider,因为它是第一个被指定的。chain_provider将会,依次地,尝试从 in_memoryuser_db 这两个provider中加载用户。

你也可以配置防火墙或独立认证机制,以使用特定的provider。再次强调,除非显式地去指定一个provider,否则始终使用第一个provider:

1
2
3
4
5
6
7
8
9
10
11
# app/config/security.yml
security:
    firewalls:
        secured_area:
            # ...
            pattern: ^/
            provider: user_db
            http_basic:
                realm: 'Secured Demo Area'
                provider: in_memory
            form_login: ~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 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>
        <firewall name="secured_area" pattern="^/" provider="user_db">
            <!-- ... -->
            <http-basic realm="Secured Demo Area" provider="in_memory" />
            <form-login />
        </firewall>
    </config>
</srv:container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// app/config/security.php
$container->loadFromExtension('security', array(
    'firewalls' => array(
        'secured_area' => array(
            // ...
            'pattern' => '^/',
            'provider' => 'user_db',
            'http_basic' => array(
                // ...
                'realm' => 'Secured Demo Area',
                'provider' => 'in_memory',
            ),
            'form_login' => array(),
        ),
    ),
));

本例中,如果用户通过HTTP认证来登录,authentication系统会使用 in_memory provider。但如果用户尝试通过表单登录,user_db 将被使用(因为它是防火墙整体上默认的)。

关于provider和防火墙配置的更多内容,参考 SecurityBundle配置信息("security"根键)。