登陆动作可以同时用来显示登陆表单并且进行处理。相应的,他必须知道所调用的环境。如果这个动作并没有在POST模式下调用(因为是由一个链接来请求的):而这正是我们在前面所讨论的情况。如果是在POST模式下请求的,那么则会由表单调用这个动作并进行相应的处理。
这个动作会由请求参数得到nickname域的值,并且查询User表来查看在数据库是否存在此用户。
将来一个密码控制将会为用户分配凭证。但是现在,这个动作所做的只是在一个会话属性中存储用户的id与nickname属性。最后,这个动作重定向到表单中隐藏中的原始referer域,这是作为一个请求参数传递的。如果这个域是空的,则会使用默认值。
这里我们需要注意这个例子中两种类型的属性集合之间的区别:request attributes($this->getRequest()->setAttribute())是为模板所保存的,而且只要答案发送到referer则会被忘记。session attributes($this->getUser()->setAttribute())是在整个用户会话生命期被保存的,而且在将来其他的动作也可以访问他们。如果我们希望了解更多的关于属性的内容,我们可以查看Symfony一书的参数保存器一节。
分配权限
用户可以登陆进askeet网站是一件好事,但是用户并不仅是因为好玩而登陆。发表一个新问题,对某一个问题表示兴趣,评价一个评论都需要登陆。而其他的动作将会向非登陆用户开放。
要将一个用户设置为经过验证的,我们需要调用sfUser对象的->setAuthenticated()方法。这个对象同时提供了一个证书机制(->addCredential()),来通过配置限制访问。Symfony一书的用户证书一节对此进行了详细的解释。
这就是下面两行的目的:
复制代码 代码如下:
$this->getContext()->getUser()->setAuthenticated(true);
$this->getContext()->getUser()->addCredential('subscriber');
当nickname被识别后,不仅用户数据被存放在会话属性中,而且这个用户也会被分配网站限制部分的访问权限。在明天我们将会看到如何限制验证用户的程序访问。
添加user/logout动作
关于->setAttribute()方法还有最后一个窍门:最后一个参数(上面例子中的subscriber)定义了属性存放的名字空间。一个名字空间不仅允许一个在另一个名字空间存在的名字指定给一个属性,而且可以使用一个命令快速移除所有这些属性:
复制代码 代码如下:
public function executeLogout()
{
$this->getUser()->setAuthenticated(false);
$this->getUser()->clearCredentials();
$this->getUser()->getAttributeHolder()->removeNamespace('subscriber');
$this->redirect('@homepage');
}
使用名字空间可以省去我们一个一个移除这些属性的麻烦:这只是一行语句。
更新布局
当前这个布局即使用户已经登陆仍然显示一个'login'链接。让我们来修正这一点。在askeet/apps/frontend/templates/layout.php文件中,修改我们在今天的指南开始时所修改的代码:
复制代码 代码如下:
<?php if ($sf_user->isAuthenticated()): ?>
<li><?php echo link_to('sign out', 'user/logout') ?></li>
<li><?php echo link_to($sf_user->getAttribute('nickname', '', 'subscriber').' profile', 'user/profile') ?></li>
<?php else: ?>
<li><?php echo link_to('sign in/register', 'user/login') ?></li>
<?php endif ?>
现在是时候进行测试了,我们可以显示程序的任何一页,点击'login'链接,输入一个可用的昵称('anonymous'为例)并且进行验证。如果窗口顶部的'login'变为'sign out',则我们所做的一切都是正确的。最后,试着注销来查看'login'链接是否再次出现。
问题组织