如何自定义你的表单登录

3.4 版本
维护中的版本

在Symfony中的认证处理中,使用 表单登录 是一种常见且灵活的方法。表单登录的每一个方面都可以被定制。下面介绍完整的默认配置。

表单登录配置参考 

要查看完整的表单登录配置,参考 SecurityBundle配置信息("security"根键)。其中一些有意思的配置选项会在下面进行解释。

成功后的重定向 

你可以使用多种配置选项去改变登录成功后的跳转页面。默认时页面会跳转回用户请求的URL(如,触发了登录表单显示的那个URL)。例如,如果用户请求 http://www.example.com/admin/post/18/edit,那么在登录成功后,用户最终会被送回 http://www.example.com/admin/post/18/edit。这是通过存储在session中的“被请求URL”来完成。如果session中没有URL(也许用户直接去的登陆页面),那么用户被重定向到默认页面,即默认的 /(即homepage)。你可以通过多种方式修改此行为。

正如前面提到的,默认时,用户将重定向回原来请求的页面。有时,这会引发问题,像是:如果有一个ajax后台请求“显示”出要成为最后访问的URL,将导致用户被重定向到那个请求上。要控制这种行为,参考 如何更改默认目标路径的行为

更改默认页 

首先,默认页(default page)可以被设置(即,如果session中没有存储上一个页面,用户就会被重定向到这个页面)。通过以下配置可以设置 default_security_target 路由:

1
2
3
4
5
6
7
8
9
# app/config/security.yml
security:
    # ...

    firewalls:
        main:
            form_login:
                # ...
                default_target_path: default_security_target
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="main">
            <form-login default-target-path="default_security_target" />
        </firewall>
    </config>
</srv:container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
 
    'firewalls' => array(
        'main' => array(
            // ...
 
            'form_login' => array(
                // ...
                'default_target_path' => 'default_security_target',
            ),
        ),
    ),
));

现在,当session中没有被设置URL时,用户将被发送到 default_security_target 路由。

始终重定向到默认页面 

通过设置 always_use_default_target_path 选项为 true,你可以不管用户请求的是什么页面,总是把URL定向到默认页面:

1
2
3
4
5
6
7
8
9
# app/config/security.yml
security:
    # ...

    firewalls:
        main:
            form_login:
                # ...
                always_use_default_target_path: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 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="main">
            <!-- ... -->
            <form-login always-use-default-target-path="true" />
        </firewall>
    </config>
</srv:container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
 
    'firewalls' => array(
        'main' => array(
            // ...
 
            'form_login' => array(
                // ...
                'always_use_default_target_path' => true,
            ),
        ),
    ),
));

使用引用的 URL 

万一之前的 URL 没有被存在 session 中,你可能希望尝试转而使用 HTTP_REFERER,因为这往往会达到相同效果。将 use_referer 设置为 true 即可完成(默认为false):

1
2
3
4
5
6
7
8
9
10
# app/config/security.yml
security:
    # ...

    firewalls:
        main:
            # ...
            form_login:
                # ...
                use_referer: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 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="main">
            <!-- ... -->
            <form-login use-referer="true" />
        </firewall>
    </config>
</srv:container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
 
    'firewalls' => array(
        'main' => array(
            // ...
            'form_login' => array(
                // ...
                'use_referer' => true,
            ),
        ),
    ),
));

从表单内控制重定向的URL 

通过为表单自身添加一个name 为 _target_path 的隐藏字段,你也可以覆写用户的重定向去处。例如,以下代码将重定向到被设置为 account 的路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{# src/AppBundle/Resources/views/Security/login.html.twig #}
{% if error %}
    <div>{{ error.message }}</div>
{% endif %}
 
<form action="{{ path('login') }}" method="post">
    <label for="username">Username:</label>
    <input type="text" id="username" name="_username" value="{{ last_username }}" />
 
    <label for="password">Password:</label>
    <input type="password" id="password" name="_password" />
 
    <input type="hidden" name="_target_path" value="account" />
 
    <input type="submit" name="login" />
</form>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- src/AppBundle/Resources/views/Security/login.html.php -->
<?php if ($error): ?>
    <div><?php echo $error->getMessage() ?></div>
<?php endif ?>
 
<form action="<?php echo $view['router']->path('login') ?>" method="post">
    <label for="username">Username:</label>
    <input type="text" id="username" name="_username" value="<?php echo $last_username ?>" />
 
    <label for="password">Password:</label>
    <input type="password" id="password" name="_password" />
 
    <input type="hidden" name="_target_path" value="account" />
 
    <input type="submit" name="login" />
</form>

现在,用户将被重定向到表单的隐藏字段值。属性值可以是相对路径,绝对路径,或是一个路由名称。通过将 target_path_parameter 选项改为其他值,你甚至可以改变表单的隐藏字段之名称(name属性):

1
2
3
4
5
6
7
8
9
# app/config/security.yml
security:
    # ...

    firewalls:
        main:
            # ...
            form_login:
                target_path_parameter: redirect_url
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 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="main">
            <!-- ... -->
            <form-login target-path-parameter="redirect_url" />
        </firewall>
    </config>
</srv:container>
1
2
3
4
5
6
7
8
9
10
11
12
13
// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
 
    'firewalls' => array(
        'main' => array(
            // ...
            'form_login' => array(
                'target_path_parameter' => 'redirect_url',
            ),
        ),
    ),
));

登录失败后的重定向 

除了登录成功后重定向用户,你也可以为登录失败(如,无效的用户名和密码被提交)的用户设置重定向。默认时,用户被重定向回登录表单本身。按如下配置,你可以把它设置成不同的路由(如 login_failure):

1
2
3
4
5
6
7
8
9
10
# app/config/security.yml
security:
    # ...

    firewalls:
        main:
            # ...
            form_login:
                # ...
                failure_path: login_failure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 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="main">
            <!-- ... -->
            <form-login failure-path="login_failure" />
        </firewall>
    </config>
</srv:container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
 
    'firewalls' => array(
        'main' => array(
            // ...
            'form_login' => array(
                // ...
                'failure_path' => 'login_failure',
            ),
        ),
    ),
));

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)