支付宝扫一扫付款
微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
一旦用户被认证,他们的凭证通常存储在session中。这意味着当session结束时,他们会被注销,下次访问程序时会被再次要求输入登录信息。使用带有 remember_me
防火墙选项的cookie,你可以让用户选择“登录进来”的停留时间比session的(周期)更长:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # app/config/security.yml
security:
# ...
firewalls:
main:
# ...
remember_me:
secret: '%secret%'
lifetime: 604800 # 1 week in seconds
path: /
# by default, the feature is enabled by checking a
# checkbox in the login form (see below), uncomment the
# following line to always enable it.
# 默认时,此功能通过在登录表单中选中一个checkbox来启用(见下文)
# 如果取消下面这行的注释,则将始终开启。
#always_remember_me: true |
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 | <!-- app/config/security.xml -->
<?xml version="1.0" encoding="utf-8" ?>
<srv:container xmlns="http://symfony.com/schema/dic/security"
xmlns:srv="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<config>
<!-- ... -->
<firewall name="main">
<!-- ... -->
<!-- 604800 is 1 week in seconds -->
<remember-me
secret="%secret%"
lifetime="604800"
path="/" />
<!-- by default, the feature is enabled by checking a checkbox
in the login form (see below), add always-remember-me="true"
to always enable it. -->
</firewall>
</config>
</srv:container> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // app/config/security.php
$container->loadFromExtension('security', array(
// ...
'firewalls' => array(
'main' => array(
// ...
'remember_me' => array(
'secret' => '%secret%',
'lifetime' => 604800, // 1 week in seconds
'path' => '/',
// by default, the feature is enabled by checking a
// checkbox in the login form (see below), uncomment
// the following line to always enable it.
//'always_remember_me' => true,
),
),
),
)); |
firewall的 remember_me
定义了如下配置选项:
secret
(必填项)app/config/parameters.yml
文件中的 secret
值。name
(默认值: REMEMBERME
)remember_me
功能,确保为每个防火墙的cookie选择不同的名称。否则,你将面临很多安全相关问题。lifetime
(默认值: 31536000
)path
(默认值: /
)/forum
, /admin
)。domain
(默认值: null
)$_SERVER
中获得的当前域。secure
(默认值: false
)true
,与此功能相关的cookie,将通过HTTPS安全连接发送至用户。httponly
(默认值: true
)true
,与此功能相关的cookie仅能通过HTTP协议被访问到。这意味着cookie不能通过脚本语言访问,比如JavaScript。remember_me_parameter
(默认值: _remember_me
)always_remember_me
(默认值: false
)true
,remember_me_parameter
的值会被忽略,不管末级用户是否想,"Remember Me" 功能将始终开启。token_provider
(默认值: null
)Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider
供你使用。让用户自由选择使用或者不使用自动登陆功能是个好主意,因为此功能并不总是恰如其分。实现它的常规办法在从登录表单中添加一个复选框(checkbox)。然后,把复选框的 name
设成 _remember_me
(或者使用你在 remember_me_parameter
中所配置的),当复选框被勾选时cookie将被自动设置,同时用户会成功登陆。所以,你的定制表单登录代码最终看上去像下面这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | {# app/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="checkbox" id="remember_me" name="_remember_me" checked />
<label for="remember_me">Keep me logged in</label>
<input type="submit" name="login" />
</form> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <!-- app/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="checkbox" id="remember_me" name="_remember_me" checked />
<label for="remember_me">Keep me logged in</label>
<input type="submit" name="login" />
</form> |
只要 cookie 仍然有效,在之后的访问中,用户将自动登录。
当用户回到你的网站时,他们将基于remember me cookie中的信息被自动认证。这可让用户访问受保护的资源,如同用户在访问过程中真的已被认证过了。
然而在某些场合,你可能想要用户在访问某资源之前再次接受认证。例如,你可能想让 “remember me” 自动登录的用户去查看账户基本信息,但如果他们想要修改信息的话就要再次经过真正意义的认证。
Security组件提供了一个很好的方法来完成此事。除了显式地赋予用户role之外,根据其认证方式,用户们会被自动分配以下roles之一:
IS_AUTHENTICATED_ANONYMOUSLY
IS_AUTHENTICATED_REMEMBERED
IS_AUTHENTICATED_FULLY
除了根据“显式分配出去的roles”(来进行访问控制),你可以使用上面这些(自动分配的)roles来进行访问控制。
如果你有 IS_AUTHENTICATED_REMEMBERED
role,那么你也会有 IS_AUTHENTICATED_ANONYMOUSLY
role。如果你有 IS_AUTHENTICATED_FULLY
role,你会有另外两个角色。换言之,这些角色代表了三个“强度递增”的认证级别。
你可以使用这些附加的roles来对网站的受访部分进行精细控制。例如,你可能希望用户在cookie被验证后能够查看他们在 /account
下的的账户,但必须提供登录细节才能够编辑其账户信息。为此,你可以对控制器的特定action使用这些角色来强化安全性。控制器的editAction,使用service context以获得保护。
下例中,这个Action仅在用户持有 IS_AUTHENTICATED_FULLY
角色时可以访问。
1 2 3 4 5 6 7 8 9 10 | // ...
use Symfony\Component\Security\Core\Exception\AccessDeniedException
// ...
public function editAction()
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
// ...
} |
如果你的程序基于Symfony标准版,你也可以使用annotations方式来保护你的控制器:
1 2 3 4 5 6 7 8 9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
/**
* @Security("has_role('IS_AUTHENTICATED_FULLY')")
*/
public function editAction($name)
{
// ...
} |
如果你同时在security配置信息中也安排了一个访问控制(access control),要求用户持有一个 ROLE_USER
role才能访问其账号功能的任意页面,那么你可能会遇到以下情况:
如果未认证(non-authenticated。或anonymously authenticated匿名认证)尝试访问账户区域,该用户将被要求进行身份认证。
一旦用户输入自己的用户名和密码,假设用户获得到了你配置的 ROLE_USER
role,这个用户将有IS_AUTHENTICATED_FULLY
role,并能够访问账户部分的任意页面,包括 editAction
控制器。
当用户返回网站时,如果其session已结束,他们将能够访问每个账户页面 — 除了编辑页面之外 — 其他页面未要求强制认证。然而,当他们试图访问 editAction
控制器时,将被迫进行“再认证”,因为他们都没有进行fully authenticated(译注:可理解为“提供登录细节”的完全认证)。
以这种方式来保护service(服务)或method(服务中的方法)之信息,参考 如何保护程序中的服务和方法。
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。