发布于 2015-12-06 07:37:08 | 231 次阅读 | 评论: 0 | 来源: 网络整理
对于每个传入的请求,Symfony 都检查每个 access_control 条目来找到一个匹配当前项的请求的 access_control。当它找到一个匹配的 access_control 项它便停止,只有第一个匹配的 access_control 用于强制执行访问。
每个 access_control 拥有几个可以配置以下两个不同条件的选项:
Symfony 中每个 access_control 条目创建了一个 RequestMatcher 用于确定是否应该对每个访问使用给定的访问控制。下面的 access_control 选项用于匹配:
路径
ip 或 ips
主机
以下面的 access_control 条目为例:
YAML:
# app/config/security.yml
security:
# ...
access_control:
- { path: ^/admin, roles: ROLE_USER_IP, ip: 127.0.0.1 }
- { path: ^/admin, roles: ROLE_USER_HOST, host: symfony\.com$ }
- { path: ^/admin, roles: ROLE_USER_METHOD, methods: [POST, PUT] }
- { path: ^/admin, roles: ROLE_USER }
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>
<!-- ... -->
<access-control>
<rule path="^/admin" role="ROLE_USER_IP" ip="127.0.0.1" />
<rule path="^/admin" role="ROLE_USER_HOST" host="symfony\.com$" />
<rule path="^/admin" role="ROLE_USER_METHOD" method="POST, PUT" />
<rule path="^/admin" role="ROLE_USER" />
</access-control>
</config>
</srv:container>
PHP:
// app/config/security.php
$container->loadFromExtension('security', array(
// ...
'access_control' => array(
array(
'path' => '^/admin',
'role' => 'ROLE_USER_IP',
'ip' => '127.0.0.1',
),
array(
'path' => '^/admin',
'role' => 'ROLE_USER_HOST',
'host' => 'symfony\.com$',
),
array(
'path' => '^/admin',
'role' => 'ROLE_USER_METHOD',
'method' => 'POST, PUT',
),
array(
'path' => '^/admin',
'role' => 'ROLE_USER',
),
),
));
对于每个传入的请求,基于 URI、 客户端的 IP 地址、 传入的主机名和请求的方法 Symfony 会决定使用哪个 access_control 。请记住,第一个匹配规则已经被使用了,并且如果 ip、 主机或方法没有被指定为一个条目,该 access_control 将匹配任何的 ip、 主机或方法:
URI | IP | 主机 | 方法 | access_control | 为什么 |
---|---|---|---|---|---|
/admin/user | 127.0.0.1 | example.com | GET | rule #1 (ROLE_USER_IP) | URI 匹配路径 IP 匹配 ip。 |
/admin/user | 127.0.0.1 | symfony.com | GET | rule #1 (ROLE_USER_IP) | 路径和 ip 仍然匹配。这也符合 ROLE_USER_HOST 条目,但只有第一个 access_control 匹配被使用了。. |
/admin/user | 168.0.0.1 | symfony.com | GET | rule #2 (ROLE_USER_HOST) | Ip 不符的第一个规则,因此使用第二个规则 (符合)。 |
/admin/user | 168.0.0.1 | symfony.com | POST | rule #2 (ROLE_USER_HOST) | 第二条规则仍然匹配。这也符合第三条规则 (ROLE_USER_METHOD),但只有第一个匹配的 access_control 被使用了。 |
/admin/user | 168.0.0.1 | example.com | POST | rule #3 (ROLE_USER_METHOD) | Ip 和主机与前两项不匹配,但和第三项 - ROLE_USER_METHOD - 匹配,并且它会被使用。 |
/admin/user | 168.0.0.1 | example.com | GET | rule #4 (ROLE_USER) | Ip、 主机和方法阻止的前三项进行匹配。但因为 URI 匹配 ROLE_USER 条目的路径模式,所以它会被使用。 |
/foo | 127.0.0.1 | symfony.com | POST | matches no entries | 它不匹配任何 access_control 规则,因为它的 URI 不匹配任何的路径值。 |
一旦 Symfony 决定了哪些 access_control 条目能匹配 (如果有的话),那么它将执行基于角色的访问限制,allow_if 和 requires_channel 选项:
role 如果用户没有所给定的角色,那么访问将会被拒绝 (在内部,将会抛出 AccessDeniedException 异常);
allow_if 如果该表达式返回 false,那么访问将会被拒绝;
如果访问被拒绝,如果一个用户还没有经过身份认证,那么系统将尝试对用户进行身份验证 (如:把用户重定向到登录页)。如果用户已经登录,则将显示 403 "拒绝访问"错误页。请参阅如何自定义错误页的详细信息。
当您需要只和某些 IP 地址或范围请求所匹配的 access_control 项,那么会出现某些特定的情况。例如,可以使用它来拒绝访问除了那些从受信任的内部服务器之外的所有请求的 URL 模式。
你会看到在下面的例子解释,ips 选项并不限制到特定的 IP 地址。相反,使用 ips 密钥意味着 access_control 条目将仅匹配此 IP 地址,并且用户会根据 access_control 列表从不同的 IP 地址依次访问它。
这里是关于您如何配置一些示例 **/internal*** URL 模式的示例,所以它只能从本地服务器的请求来访问:
YAML:
# app/config/security.yml
security:
# ...
access_control:
#
- { path: ^/internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [127.0.0.1, ::1] }
- { path: ^/internal, roles: ROLE_NO_ACCESS }
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>
<!-- ... -->
<access-control>
<rule path="^/esi" role="IS_AUTHENTICATED_ANONYMOUSLY"
ips="127.0.0.1, ::1" />
<rule path="^/esi" role="ROLE_NO_ACCESS" />
</access-control>
</config>
</srv:container>
PHP:
// app/config/security.php
$container->loadFromExtension('security', array(
// ...
'access_control' => array(
array(
'path' => '^/esi',
'role' => 'IS_AUTHENTICATED_ANONYMOUSLY',
'ips' => '127.0.0.1, ::1'
),
array(
'path' => '^/esi',
'role' => 'ROLE_NO_ACCESS'
),
),
));
这里描述了当路径是 /internal/something 并且来自外部 IP 地址 10.0.0.1 的时候该如何去工作:
第一个访问控制规则将被忽略,因为虽然路径匹配但是 IP 地址不匹配,或者 IPs 列出的地址不匹配;
但如果同一请求来自 127.0.0.1 或:: 1 (IPv6 环回地址):
现在,作为路径和 ip 匹配启用的第一次的访问控制规则: 允许访问的用户总是有 IS_AUTHENTICATED_ANONYMOUSLY 的作用。
一旦 access_control 条目相匹配,你可以通过角色秘钥或使用更复杂的逻辑与表达式中 allow_if 密钥拒绝访问:
YAML:
# app/config/security.yml
security:
# ...
access_control:
-
path: ^/_internal/secure
allow_if: "'127.0.0.1' == request.getClientIp() or has_role('ROLE_ADMIN')"
XML:
<access-control>
<rule path="^/_internal/secure"
allow-if="'127.0.0.1' == request.getClientIp() or has_role('ROLE_ADMIN')" />
</access-control>
PHP:
'access_control' => array(
array(
'path' => '^/_internal/secure',
'allow_if' => '"127.0.0.1" == request.getClientIp() or has_role("ROLE_ADMIN")',
),
),
在这种情况下,当用户试图从 /_internal/secure 开始访问任何 URL,如果 IP 地址是 127.0.0.1,或者如果用户拥有 ROLE_ADMIN 的角色,他们将只被授予访问权限。
在这个表达式中,您可以访问不同的变量和函数并且包括 Symfony 中的请求对象 (见请求)。
关于其他的函数和变量的列表,请参阅函数和变量。
您还可以要求用户通过 SSL 访问 URL;只需要使用任何 access_control 条目中的 requires_channel 参数。如果该 access_control 匹配成功并且请求使用的是 http 通道,用户将被重定向到 https:
YAML:
# app/config/security.yml
security:
# ...
access_control:
- { path: ^/cart/checkout, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
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">
<access-control>
<rule path="^/cart/checkout"
role="IS_AUTHENTICATED_ANONYMOUSLY"
requires-channel="https" />
</access-control>
</srv:container>
PHP:
// app/config/security.php
$container->loadFromExtension('security', array(
'access_control' => array(
array(
'path' => '^/cart/checkout',
'role' => 'IS_AUTHENTICATED_ANONYMOUSLY',
'requires_channel' => 'https',
),
),
));