【发布时间】:2011-02-09 10:59:45
【问题描述】:
我将如何全局保护我的所有控制器(除了我的登录控制器)以确保我的应用程序在所有方面都是安全的(没有隐藏的 ajax 调用后门等)。我以为我可以把它放在我的引导文件中,但这感觉不对?我试图避免向每个控制器添加任何代码。
建议?
【问题讨论】:
标签: php security zend-framework
我将如何全局保护我的所有控制器(除了我的登录控制器)以确保我的应用程序在所有方面都是安全的(没有隐藏的 ajax 调用后门等)。我以为我可以把它放在我的引导文件中,但这感觉不对?我试图避免向每个控制器添加任何代码。
建议?
【问题讨论】:
标签: php security zend-framework
编辑:这是对@singles 响应的补充。
您必须了解有两种不同的东西。 Auth 和 Acl。 Auth 告诉您谁是用户,例如,您可以将没有 Auth 的用户重定向到您的登录控制器,并在登录后设置一个 auth 身份。然后 Acl 系统根据 Auth 数据(可能是用户 ID 或角色,存储在 Auth 存储中)做出是/否决定。
一个不错的解决方案是拥有 2 个控制器插件(在引导程序上以良好的顺序注册,Auth 然后 Acl)。如果您不使用控制器插件,则必须在需要时在每个控制器中调用 Acl 检查。如果您总是需要它,请使用插件。
在您的Auth 插件 中实现preDispatch() 以设置例如匿名身份,如果您没有从Zend_Auth 返回身份。
这是一个真实的sn-p代码:
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$module = $request->getModuleName();
$controller = $request->getControllerName();
$action = $request->getActionName();
$auth = Zend_Auth::getInstance();
if (!$auth->hasIdentity()) {
// set a default anonymous identity
$auth->getStorage()->write(array('name' => 'anonymous','role' => 1,));
}
(...)
对于Acl 控制器插件,任务也在preDispatch() 中。您可以为每个请求的 url 启动 acl 检查(因此对于每个用户请求,甚至是 ajax)。这是一个部分的 sn-p,所以这只是你如何处理事情的一个例子:
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$controller = $request->controller;
$module = $request->module;
$action = $request->action;
// here you should code something nice retrieving you Zend_Acl object
// with some caching options maybe, building roles, ressources, etc
$this->_acl = $this->getAcl();
if (!$this->_acl->isCurrentUserAllowed($module,'see')) {
$auth = Zend_Auth::getInstance();
$identity = $auth->hasIdentity('identity')? $auth->getIdentity() : null;
if(isset($identity)) {
if($identity['name'] == 'anonymous') {
// WARNING: avoid infinite redirect loops on login page
if (!($request->getControllerName() == 'login'
&& $request->getActionName()=='login'
&& $request->getModuleName() == 'default')) {
$request->setControllerName('login')
->setActionName('login')
->setModuleName('default');
return;
(...)
在这个系统中,最后一个重要的部分是 LoginController,如果成功登录,您应该启动身份记录:
(...)
$auth = Zend_Auth::getInstance();
Zend_Session::regenerateId();
$storage = $auth->getStorage();
$rowobject = $authAdapter->getResultRowObject(null,'passwd');
$storage->write((array)$rowobject);
(...)
【讨论】:
anonymous user 的想法,并保证我会在我的作品中使用它:)
您应该为此编写 ACL 插件并将其注册到前端控制器中。如果您将此类功能实现为插件,您将可以灵活地在下一个应用程序中使用它 - 无需从自定义控制器扩展每个控制器。
资源:
1.Front Controller Plugins in Zend Framework - ZF 中插件的工作原理
2. Zend_Acl / Zend_Auth example scenario - ACL 插件的许多可能实现之一。
3. Google - 还有很多其他资源
【讨论】:
嗯,你需要有一个进入你的系统的入口点:)
这可以通过扩展 Zend_Controller_Action 来实现,比如说:
abstract class MyController extends Zend_Controller_Action {
public function preDispatch(){
// do the logic
}
}
现在你的每个控制器只需要扩展 MyController 就很安全了。
【讨论】:
我在一个实现中的方法是在我的应用程序路径中创建一个名为 Auth.php 的文件。然后我打开了我想要保护的每个控制器并添加了这一行
include_once APPLICATION_PATH . '/Auth.php';
调用 parent::init() 之前的 init() 方法。
至于 Auth.php 文件本身,它基本上是使用 Zend_Auth 来进行认证的。成功后,我会保存用户的身份以供以后在应用程序中使用
$this->view->assign('myIdentity', Zend_Auth::getInstance()->getIdentity());
如果失败,我会重定向到登录页面并传递一些参数,以便登录页面在我登录后知道将我发送到哪里。
这不是一个优雅的解决方案,但它可靠且相对快速且易于实施。
【讨论】: