安全(Security)
Symfony的安全系统(security system)是非常强大的,但在设置它时也可能令人迷惑。在本大章中,你将学会如何一步步地设置程序的security,从配置防火墙(firewall)以及加载用户,到拒绝访问和取到用户对象。根据你的需求,有时在进行初始化设置时是痛苦的。然而一旦(配置)完成,Symfony的security系统在用起来时,则是既灵活又(希望能够)有乐趣。
由于有很多话要说,本章按几个大部头来组织:
初始化
security.yml
的设置 (security.yml
的设置 (authentication/验证 );拒绝访问你的程序 (authorization/授权 );
获取当前的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.
authentication/验证
authorization/授权
);获取当前的User对象;它们被细分为许多小块内容(但仍然令人着迷),像是 logging out 和 加密用户密码。
1)初始化security.yml的设置 (Authentication/验证) ¶
app/config/security.yml
中进行配置。默认的配置是这样的:🎜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: ~🎜
firewalls
键是security配置的 🎜核心🎜。dev
防火墙并不重要,它只是确保Symfony开发工具 - 也就是居于 /_profiler
和 /_wdt
之下的那些URL将不会被你的security所阻止。🎜🎜🎜🎜你也可以针对请求中的其他细节来匹配一个请求(如 host主机)。阅读 如何把防火墙限制在特定请求🎜 以了解更多内容和例程。🎜🎜🎜🎜所有其他的URL将被 default
防火墙中处理(没有 pattern
键意味着它可以匹配🎜所有🎜 URL)。你可以认为防火墙就是你的security系统,因此通常只有一个主力防火墙就变得有意义了。但这并🎜不🎜 意味着每一个URL都需要验证 - anonymous
键可以搞定这个。事实上,如果你现在去首页,是可以访问的,并将看到你以 anon.
身份“通过了验证”。不要被Authenticated旁边的“Yes”愚弄,你仍然只是个匿名用户:🎜🎜🎜🎜🎜后面你将学习到如何拒绝访问特定URL或控制器(中的action)。🎜🎜🎜🎜Security是🎜高度🎜 可配置的,在 🎜Security配置参考🎜 里展示了全部配置选项,并有一些附加说明。🎜🎜🎜A) 配置“如何令用户接受验证” ¶
防火墙的主要工作是去配置如何 让你的用户能够被验证。它们是否需要使用登录表单?或是HTTP basic验证?抑或一个API token?还是上面所有这些?
让我们从HTTP basic验证开始(老旧的弹出框)展开。要激活此功能,添加 http_basic
到firewall下面:http_basic
到firewall下面:
// 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>'); }}
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>
/admin
下创建一个新页面 。例如,如果你使用annotations,创建下例代码:YAML:# app/config/security.ymlsecurity: # ... firewalls: # ... default: # ... access_control: # require ROLE_ADMIN for /admin* - { path: ^/admin, roles: ROLE_ADMIN }
接下来,在 security.yml
中添加一个 access_control
入口,以令用户必先登录方可访问URL:
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: password: ryanpass roles: 'ROLE_USER' admin: password: kitten roles: 'ROLE_ADMIN' # ...
你将学到关于 ROLE_ADMIN
以及后面的 2) 拒绝访问, Roles和其他授权 小节中的“拒绝访问”等更多内容。
太好了,如果你去访问 /admin
PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'encoders' => array( 'Symfony\Component\Security\Core\User\User' => 'plaintext', ), // ...));
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> <!-- ... --> <encoder class="Symfony\Component\Security\Core\User\User" algorithm="plaintext" /> <!-- ... --> </config></srv:container>
YAML:app/config/security.ymlsecurity: # ... encoders: Symfony\Component\Security\Core\User\User: plaintext # ...
/admin
下创建一个新页面 。例如,如果你使用annotations,创建下例代码:PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'encoders' => array( 'Symfony\Component\Security\Core\User\User' => array( 'algorithm' => 'bcrypt', 'cost' => 12, ) ), // ...));
接下来,在 security.yml
中添加一个 access_control
入口,以令用户必先登录方可访问URL:
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> <!-- ... --> <encoder class="Symfony\Component\Security\Core\User\User" algorithm="bcrypt" cost="12" /> <!-- ... --> </config></srv:container>
YAML:# app/config/security.ymlsecurity: # ... encoders: Symfony\Component\Security\Core\User\User: algorithm: bcrypt cost: 12
1
ROLE_ADMIN
以及后面的 2) 拒绝访问, Roles和其他授权如何建立一个传统的登录表单。还支持其他什么(验证)方式?参考 Configuration Reference
或者B) 配置“如何加载用户” ¶
当你在输入用户名时,Symfony就要从某个地方加载用户的信息。这就是所谓的“user provider”,由你来负责配置它。Symfony有一个内置方式来 从数据库中加载用户,但也可以 创建你自己的user provider。
最简单的方式(但有很多限制),是配置Symfony从 security.yml
文件里直接加载写死在其中的用户。这被称为“in memory” provider,但把它观想为“in configuration” provider更合适些security.yml
文件里直接加载写死在其中的用户。这被称为“in memory” provider,但把它观想为“in configuration” provider更合适些
$ php bin/console security:encode-password
PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'providers' => array( 'in_memory' => array( 'memory' => array( 'users' => array( 'ryan' => array( 'password' => 'a$LCY0MefVIEc3TYPHV9SNnuzOfyr2p/AXIGoQJEDs4am4JwhNz/jli', 'roles' => 'ROLE_USER', ), 'admin' => array( 'password' => 'a$cyTWeE9kpq1PjqKFiWUZFuCRPwVyAZwm4XzMZ1qPUFl7/flCM3V0G', '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="a$LCY0MefVIEc3TYPHV9SNnuzOfyr2p/AXIGoQJEDs4am4JwhNz/jli" roles="ROLE_USER" /> <user name="admin" password="a$cyTWeE9kpq1PjqKFiWUZFuCRPwVyAZwm4XzMZ1qPUFl7/flCM3V0G" roles="ROLE_ADMIN" /> </memory> </provider> </config></srv:container>
类似 firewalls
,你可以拥有多个 providers
,但你几乎只需要一个。如果你确实 拥有多个,你可以在防火墙的 provider
键(如 provider:in_memory
YAML:# app/config/security.ymlsecurity: # ... providers: in_memory: memory: users: ryan: password: a$LCY0MefVIEc3TYPHV9SNnuzOfyr2p/AXIGoQJEDs4am4JwhNz/jli roles: 'ROLE_USER' admin: password: a$cyTWeE9kpq1PjqKFiWUZFuCRPwVyAZwm4XzMZ1qPUFl7/flCM3V0G roles: 'ROLE_ADMIN'
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>类似
firewalls
,你可以拥有多个 providers
,但你几乎只需要一个。如果你确实 拥有多个,你可以在防火墙的 provider
键(如 provider:in_memory
)之下,配置“要使用哪 来了解multiple providers设置的全部细节。🎜🎜🎜试着以用户名 admin
和密码 kitten
来登录。你应该看到一个错误!admin
和密码 kitten
来登录。你应该看到一个错误!
No encoder has been configured for account "SymfonyComponentSecurityCoreUserUser"
要修复此问题 ,添加一个 encoders
健:
YAML:# app/config/security.ymlsecurity: # ... firewalls: # ... default: # ... access_control: # require ROLE_ADMIN for /admin* - { path: ^/admin, roles: ROLE_ADMIN }
PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'access_control' => array( array('path' => '^/admin/users', 'role' => 'ROLE_SUPER_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> <!-- ... --> <rule path="^/admin/users" role="ROLE_SUPER_ADMIN" /> <rule path="^/admin" role="ROLE_ADMIN" /> </config></srv:container>
User providers加载用户信息,并将其置于一个 User
对象中。如果你从数据库中加载用户 或者 从其他来源加载,你需要使用自定义的User类。但当你使用“in memory” provider时,它直接给了你一个 SymfonyComponentSecurityCoreUserUser
对象。
无论你使用什么样的User类,你都需要去告诉Symfony它们的密码加密算法是什么。在本例中,密码只是明文的文本,但很快,你要把它改成 bcrypt
。
如果你现在刷新,你就会登录进来!web除错工具栏会告诉你,你是何人,你的roles(角色)是什么:
由于此URL需要的是 ROLE_ADMIN
,如果你登录的是 ryan
用户,将被拒绝访问。更多内容参考后面的 [URL受到保护的条件(access_control](#catalog9)。
从数据库加载用户 ¶
如果你想通过Doctrine Orm加载用户,很容易!参考 如何从数据库中(Entity Provider)加载Security系统之用户 以了解全部细节。
C) 对用户密码进行加密 ¶
不管用户是存储在 security.yml
里,数据库里还是其他地方,你都需要去加密其密码。堪用的最好算法是 bcrypt
No encoder has been configured for account "SymfonyComponentSecurityCoreUserUser"
要修复此问题 ,添加一个
encoders
健:YAML:# app/config/security.ymlsecurity: # ... access_control: - { path: ^/admin/users, roles: ROLE_SUPER_ADMIN } - { path: ^/admin, roles: ROLE_ADMIN }
// ... public function helloAction($name){ // The second parameter is used to specify on what object the role is tested. // 第二个参数用于指定“要将role作用到什么对象之上” $this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!'); // Old way / 老办法: // if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { // throw $this->createAccessDeniedException('Unable to access this page!'); // } // ...}
// ...use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; /** * @Security("has_role('ROLE_ADMIN')") */public function helloAction($name){ // ...}
User providers加载用户信息,并将其置于一个
User
对象中。如果你从数据库中加载用户 或者 从其他来源加载,你需要使用自定义的User类。但当你使用“in memory” provider时,它直接给了你一个 SymfonyComponentSecurityCoreUserUser
对象。bcrypt
。如果你现在刷新,你就会登录进来!web除错工具栏会告诉你,你是何人,你的roles(角色)是什么:如果你想通过Doctrine Orm加载用户,很容易!参考 如何从数据库中(Entity Provider)加载Security系统之用户 以了解全部细节。C) 对用户密码进行加密 ¶security.yml 里,数据库里还是其他地方,你都需要去加密其密码。堪用的最好算法是 bcrypt : | if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) { throw $this->createAccessDeniedException(); } // ...} |
PHP:<?php if ($view['security']->isGranted(new Expression(
'"ROLE_ADMIN" in roles or (user and user.isSuperAdmin())'))): ?>
<a href="...">Delete</a><?php endif; ?>
🎜🎜🎜🎜Twig:{% if is_granted(expression(
'"ROLE_ADMIN" in roles or (user and user.isSuperAdmin())')) %}
<a href="...">Delete</a>{% endif %}
🎜🎜🎜🎜🎜它将带给你下面这样(密码被加密)的东东:
public function indexAction(){ if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) { throw $this->createAccessDeniedException(); } $user = $this->getUser(); // the above is a shortcut for this / 上面的写法是通过以下取法(再进行授权)的快捷方式 $user = $this->get('security.token_storage')->getToken()->getUser();}
use Symfony\Component\HttpFoundation\Response; // ... public function indexAction(){ // ... return new Response('Well hi there '.$user->getFirstName());}
public function indexAction(UserInterface $user = null){ // $user is null when not logged-in or anon. // 当用户没有登陆,或者是anno.时,$user是null}
现在一切都和以前一样。但如果你有动态用户(如,数据库中的),其密码在入库之前,你如何才能程序化的加密之呢?别担心,参考 手动加密密码 以了解细节。
此种方式的加密算法能否受到支持取决于你的PHP版本,但是包括 hash_algos PHP函数所返回的算法,以及一些其他(如 bcrypt
)都受到支持。参考 Security参考bcrypt
)都受到支持。参考 Security参考 中的 encoders
中的 encoders
选项键作为示例。
针对不同的用户,分别使用不同的算法也是可能的。参考 如何动态选择密码加密算法 以了解更多细节。
D) 配置完成! ¶
祝贺你!现在你有了一个可以使用的基于HTTP basic验证、并从 security.yml
文件中加载用户的“验证系统”了。security.yml
文件中加载用户的“验证系统”了。
根据你的设置,尚有后续步骤:
在 授权 小节了解如何拒绝访问(deny access)、加载用户对象,以及操作Roles;
2) 拒绝访问,Roles和其他授权方式 ¶
现在,用户可以通过 http_basic
或者其他方式来登录你的程序。了不起呀!现在你需要学习如何拒绝访问(deny access)并且能与User对象一起工作。这被称为authorization(授权),它的工作是决定用户是否可以访问某些资源(如一个URL、一个model对象、一个被调用的方法等...)。
授权过程分为两个不同的方面:
用户在登录时收到一组特定的Roles(角色。如
ROLE_ADMIN
)。你添加代码,以便某个资源(例如url、控制器)需要一个特定“属性”(多数时候就是一个类似
ROLE_ADMIN
的role)才能被访问到。
除了roles(如 ROLE_ADMIN
),你还可以使用其他属性/字符串来(如 EDIT
根据你的设置,尚有后续步骤:
- 配置用户登录的不同方式,例如 登录表单
2) 拒绝访问,Roles和其他授权方式 ¶🎜
🎜现在,用户可以通过http_basic
或者其他方式来登录你的程序。了不起呀!现在你需要学习如何拒绝访问(deny access)并且能与User对象一起工作。这被称为authorization(授权),它的工作是决定用户是否可以访问某些资源(如一个URL、一个model对象、一个被调用的方法等...)。🎜🎜授权过程分为两个不同的方面:🎜- 🎜用户在登录时收到一组特定的Roles(角色。如
ROLE_ADMIN
)。🎜 - 🎜你添加代码,以便某个资源(例如url、控制器)需要一个特定“属性”(多数时候就是一个类似
ROLE_ADMIN
的role)才能被访问到。🎜
ROLE_ADMIN
),你还可以使用其他属性/字符串来(如 EDIT
)来保护一个资源,并且通过使用voters或Symfony的ACL系统,来令它们生效。这在你需要检查用户A能否“编辑”对象B(如,id为5的产品)时极为好用。参考 🎜Access Control Lists (ACLs):保护单个数据库对象🎜。🎜🎜🎜Roles/角色 ¶
当有用户登录时,他们会接收到一组roles(如 ROLE_ADMIN
)。在上例中,这些(roles)都被写死到 security.yml
中了。如果你从数据库中加载用户,它们应该存在了表的某一列中。ROLE_ADMIN
)。在上例中,这些(roles)都被写死到 security.yml
中了。如果你从数据库中加载用户,它们应该存在了表的某一列中。
你要分给一个用户的所有roles,一定要以 ROLE_
前缀开始。否则,它们不会被Symfony的Security系统按常规方式来操作(除非使用高级手段,否则你把 FOO
这样的role分给一个用户,然后像 下面这样 去检查 FOO
是行不通的)。
roles很简单,而且基本上都是你根据需要自行创造的字符串。例如,如果你打算限制访问你网站博客的admin部分,可以使用ROLE_BLOG_ADMIN
这个role来进行保护。role毋须在其他地方定义-你就可以开始用它了。
确保每个用户至少有一个 角色,否则他们会被当作未验证之人。常见的做法就是给每个 普通用户一个 ROLE_USER
。
你还可以指定role层级,此时,拥有某些roles意味着你同时拥有了其他的roles。
添加代码以拒绝访问 ¶
要拒绝访问(deny access)某些东东,有两种方式可以实现:
使用security.yml中的access_control,即可使用URL的条件保护(如
/admin/*
)。这虽然容易,但灵活性不足;
通过条件匹配来保护URL(access_control) ¶
对程序的某一部分进行保护时的最基本方法是对URL进行完整的条件匹配。之前你已看到,任何匹配了正则表达式 ^/admin
的页面都需要 ROLE_ADMIN
ROLE_
前缀开始。否则,它们不会被Symfony的Security系统按常规方式来操作(除非使用高级手段,否则你把 FOO
这样的role分给一个用户,然后像 下面这样FOO
是行不通的)。ROLE_BLOG_ADMIN
这个role来进行保护。role毋须在其他地方定义-你就可以开始用它了。ROLE_USER
。- 🎜使用security.yml中的access_control🎜,即可使用URL的条件保护(如
/admin/*
)。这虽然容易,但灵活性不足;🎜 - 🎜在代码中使用 security.authorization_checker 服务🎜;🎜
通过条件匹配来保护URL(access_control) ¶🎜
🎜对程序的某一部分进行保护时的最基本方法是对URL进行完整的条件匹配。之前你已看到,任何匹配了正则表达式^/admin
的页面都需要 ROLE_ADMIN
:🎜// yay! Use this to see if the user is logged in// 耶!使用这个来查看用户是否已登陆if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) { throw $this->createAccessDeniedException();} // boo :(. Never check for the User object to see if they're logged in// 哄!:(. 切勿通过检查User对象来判断用户是否已登陆if ($this->getUser()) { }
PHP:<?php if ($view['security']->isGranted('IS_AUTHENTICATED_FULLY')): ?> <p>Username: <?php echo $app->getUser()->getUsername() ?></p><?php endif; ?>🎜🎜🎜🎜🎜
Twig:{% if is_granted('IS_AUTHENTICATED_FULLY') %} <p>Username: {{ app.user.username }}</p>{% endif %}🎜🎜🎜🎜🎜
能够保护全部(URL所属的)区域固然很好,但你可能还想 保护控制器的某一action。
如果需要,你可以定义任意多个URL匹配条件 - 每个条件都是正则表达式。但是,仅仅有一个会被匹配。Symfony会从(文件中的)顶部开始寻找,一旦发现 access_control
中的某个入口与URL相匹配,就立即结束。access_control
中的某个入口与URL相匹配,就立即结束。
PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'firewalls' => array( 'secured_area' => array( // ... 'logout' => array('path' => '/logout', 'target' => '/'), ), ),));
Twig:<!-- 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"> <!-- ... --> <logout path="/logout" target="/" /> </firewall> </config></srv:container>
YAML:# app/config/security.ymlsecurity: # ... firewalls: secured_area: # ... logout: path: /logout target: /
在path中加了一个 ^
是指,仅当URL“按照正则条件那样起头”时,才会匹配到。例如,一个path若只有 /admin
(不包含 ^
)则会匹配到 /admin/foo
但同时也匹配了 /foo/admin
这种。
保护控制器和代码中的其他部分 ¶
在控制器中你可以轻松谢绝访问:
PHP:// app/config/routing.phpuse Symfony\Component\Routing\RouteCollection;use Symfony\Component\Routing\Route; $collection = new RouteCollection();$collection->add('logout', new Route('/logout')); return $collection;
两种情况下,一个特殊的 AccessDeniedException
会被抛出,这最终触发了Symfony内部的一个403 HTTP响应。
就是这样!如果是尚未登录的用户,他们会被要求登录(如,重定向到登录页面)。如果他们已经 登录,但不具备 ROLE_ADMIN
角色,则会被显示403拒绝访问页面(此页可以 自定义)。如果他们已登录同时拥有正确的roles,代码就会继续执行。
多亏了SensioFrameworkExtraBundle,你可以在控制器中使用annotations
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://Symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://Symfony.com/schema/routing http://Symfony.com/schema/routing/routing-1.0.xsd"> <route id="logout" path="/logout" /></routes>
参考 FrameworkExtraBundle 以了解更多。
模版中的访问控制 ¶
如果你想在模版中检查当前用户是否具有一个role,可以使用内置的 is_granted()
YAML:# app/config/routing.ymllogout: path: /logout
PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'role_hierarchy' => array( 'ROLE_ADMIN' => 'ROLE_USER', 'ROLE_SUPER_ADMIN' => array( 'ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH', ), ),));
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> <!-- ... --> <role id="ROLE_ADMIN">ROLE_USER</role> <role id="ROLE_SUPER_ADMIN">ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH</role> </config></srv:container>在path中加了一个
^
是指,仅当URL“按照正则条件那样起头”时,才会匹配到。例如,一个path若只有 /admin
(不包含 ^
)则会匹配到 /admin/foo
但同时也匹配了 /foo/admin
这种。🎜