安全(Security)


Symfony的安全系统(security system)是非常强大的,但在设置它时也可能令人迷惑。在本大章中,你将学会如何一步步地设置程序的security,从配置防火墙(firewall)以及加载用户,到拒绝访问和取到用户对象。根据你的需求,有时在进行初始化设置时是痛苦的。然而一旦(配置)完成,Symfony的security系统在用起来时,则是既灵活又(希望能够)有乐趣。

由于有很多话要说,本章按几个大部头来组织:

  1. 初始化 security.yml 的设置 (authentication/验证 );

  2. 拒绝访问你的程序 (authorization/授权 );

  3. 获取当前的User对象;

它们被细分为许多小块内容(但仍然令人着迷),像是 logging out加密用户密码

1)初始化security.yml的设置 (Authentication/验证) 

security系统在 app/config/security.yml 中进行配置。默认的配置是这样的:

PHP:// app/config/security.php$container->loadFromExtension('security', array(
    'providers' => array(
        'in_memory' => array(
            'memory' => null,
        ),
    ),
    'firewalls' => array(
        'dev' => array(
            'pattern'    => '^/(_(profiler|wdt)|css|images|js)/',
            'security'   => false,
        ),
        'default' => array(
            'anonymous'  => null,
        ),
    ),));
XML:<!-- 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="in_memory">
            <memory />
        </provider>         <firewall name="dev"            pattern="^/(_(profiler|wdt)|css|images|js)/"            security="false" />         <firewall name="default">
            <anonymous />
        </firewall>
    </config></srv:container>
YAML:# app/config/security.ymlsecurity:
    providers:
        in_memory:
            memory: ~
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        default:
            anonymous: ~

firewalls 键是security配置的 核心dev 防火墙并不重要,它只是确保Symfony开发工具 - 也就是居于 /_profiler/_wdt 之下的那些URL将不会被你的security所阻止。

你也可以针对请求中的其他细节来匹配一个请求(如 host主机)。阅读 如何把防火墙限制在特定请求 以了解更多内容和例程。

所有其他的URL将被 default 防火墙中处理(没有 pattern 键意味着它可以匹配所有 URL)。你可以认为防火墙就是你的security系统,因此通常只有一个主力防火墙就变得有意义了。但这并 意味着每一个URL都需要验证 - anonymous 键可以搞定这个。事实上,如果你现在去首页,是可以访问的,并将看到你以 anon. 身份“通过了验证”。不要被Authenticated旁边的“Yes”愚弄,你仍然只是个匿名用户:

11.png

后面你将学习到如何拒绝访问特定URL或控制器(中的action)。

Security是高度 可配置的,在 Security配置参考 里展示了全部配置选项,并有一些附加说明。

A) 配置“如何令用户接受验证” 

防火墙的主要工作是去配置如何 让你的用户能够被验证。它们是否需要使用登录表单?或是HTTP basic验证?抑或一个API token?还是上面所有这些?

让我们从HTTP basic验证开始(老旧的弹出框)展开。要激活此功能,添加 http_basic 到firewall下面:

PHP:// app/config/security.php$container->loadFromExtension('security', array(
    // ...
    'firewalls' => array(
        // ...
        'default' => array(
            'anonymous'  => null,
            'http_basic' => null,
        ),
    ),));
XML:<!-- 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="default">
            <anonymous />
            <http-basic />
        </firewall>
    </config></srv:container>
YAML:# app/config/security.ymlsecurity:    # ...
    firewalls:        # ...
        default:
            anonymous: ~
            http_basic: ~
真简单!要测试效果,你需要让用户登录并看到页面。为了让事情变的有趣,在 /admin 下创建一个新页面 。例如,如果你使用annotations,创建下例代码:
// src/AppBundle/Controller/DefaultController.php
// ... use 
Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\Response; class DefaultController extends Controller{
   /**
     * @Route("/admin")
     */
    public function adminAction()
    {
        return new Response('<html><body>Admin page!</body></html>');
    }}

接下来,在 security.yml 中添加一个 access_control 入口,以令用户必先登录方可访问URL:

PHP:// app/config/security.php$container->loadFromExtension('security', array(
    // ...
    'firewalls' => array(
        // ...
        'default' => array(
            // ...
        ),
    ),
   'access_control' => array(
       // require ROLE_ADMIN for /admin*
        array('path' => '^/admin', 'role' => 'ROLE_ADMIN'),
    ),));
XML:<!-- 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="default">
            <!-- ... -->
        </firewall>         <!-- require ROLE_ADMIN for /admin* -->
        <rule path="^/admin" role="ROLE_ADMIN" />
    </config></srv:container>
YAML:# app/config/security.ymlsecurity:    # ...
    firewalls:        # ...
        default:            # ...
    access_control:        # require ROLE_ADMIN for /admin*
        - { path: ^/admin, roles: ROLE_ADMIN }

你将学到关于 ROLE_ADMIN 以及后面的 2) 拒绝访问, Roles和其他授权 小节中的“拒绝访问”等更多内容。

太好了,如果你去访问 /admin,会看到HTTP Basic验证的弹出式登录:

222.png

但是,你是以何种身份登录进来?用户(信息)又来自哪里呢?

想要使用一个传统的form表单?很好!参考 如何建立一个传统的登录表单。还支持其他什么(验证)方式?参考 Configuration Reference 或者 构建你自己的

如果你的程序是通过诸如Google,Facebook或者Twitter等三方服务来完成登录,参阅 HWIOAuthBundle 社区bundle。

B) 配置“如何加载用户” 

当你在输入用户名时,Symfony就要从某个地方加载用户的信息。这就是所谓的“user provider”,由你来负责配置它。Symfony有一个内置方式来 从数据库中加载用户,但也可以 创建你自己的user provider

最简单的方式(但有很多限制),是配置Symfony从 security.yml 文件里直接加载写死在其中的用户。这被称为“in memory” provider,但把它观想为“in configuration” provider更合适些

PHP:// app/config/security.php$container->loadFromExtension('security', array(
    'providers' => array(
        'in_memory' => array(
            'memory' => array(
                'users' => array(
                    'ryan' => array(
                        'password' => 'ryanpass',
                        'roles' => 'ROLE_USER',
                    ),
                    'admin' => array(
                        'password' => 'kitten',
                        'roles' => 'ROLE_ADMIN',
                    ),
                ),
            ),
        ),
    ),
    // ...));
XML:<!-- 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="in_memory">
            <memory>
                <user name="ryan" password="ryanpass" roles="ROLE_USER" />
                <user name="admin" password="kitten" roles="ROLE_ADMIN" />
            </memory>
        </provider>
        <!-- ... -->
    </config></srv:container>
YAML:# app/config/security.ymlsecurity:
    providers:
        in_memory:
            memory:
                users:
                    ryan:
                     &nbs