具有两个模型会话的 Cakephp 身份验证组件
Posted
技术标签:
【中文标题】具有两个模型会话的 Cakephp 身份验证组件【英文标题】:Cakephp auth component with two models session 【发布时间】:2012-05-19 06:30:19 【问题描述】:我有两个 cakephp2 应用程序在同一个数据库上运行,但是有不同的 Auth 表和不同的 $this->Auth->userModel 值。 身份验证运行良好,一个应用程序的用户无法登录其他应用程序。
但是.. 由于应用程序使用相同的 CAKEPHP 会话 cookie,会发生这种情况: 当应用程序“一”的用户登录时,它可以访问应用程序“二”中的任何受 Auth 保护的操作!
我可能会使用不同的用户角色和 cookie 名称。 但是,为什么 Auth 组件在检查会话时忽略 Auth->userModel 设置?有没有办法将其配置为在这种情况下正常工作?
提前感谢您的任何建议。
【问题讨论】:
我不知道它是否与此有关,但是当 AuthComponent 将用户存储到会话时,它总是使用User
无论用户模型名称实际上是什么 - 它的硬-编码。
那是错误的@tigrang,至少对于 2.0。
我发誓前几天在查看源代码时看到它是硬编码的 - 应该仔细检查一下,我的错。
请参阅book.cakephp.org/2.0/en/core-libraries/components/… 并且它在 1.3 年前也已修复,这实际上是一个问题 - 在过去。 :)
【参考方案1】:
如果没有另外配置,AuthComponent 会将经过身份验证的用户记录写入 CakePHP 2 中的 Auth.User
会话密钥。But it can be changed:
AuthComponent::sessionKey
存储当前用户记录的会话密钥名称。如果未指定,则为“Auth.User”。
(在 CakePHP 1.3 中 this was different: Auth.$userModel name
)
因此,如果您的应用共享一个 Session,如果 cookie 名称和 Security.salt
匹配,则将共享登录记录。
解决这个问题有两种可能:
分离登录
只需为您的两个模型设置不同的AuthComponent::sessionKey
。这将允许他们单独保留已登录的用户
分离会话
为两个应用程序配置不同的 Cookie 名称和 Salts,因此它们的会话不能相互覆盖。这可能是更简洁的解决方案,因为它还涵盖了其他会话密钥被双重使用的风险。
【讨论】:
会话密钥不会创建新的或不同的会话,而只是更改当前会话中身份验证数据的存储位置。 是的,完全正确。这将防止两个应用程序的身份验证受到干扰。创建一个完全不同的会话是我的第二个解决方案。 您的第一个解决方案成功了!我做了: AuthComponent::$sessionKey = 'Auth.MyCustomModel' 如何在 cakephp 3 中使用会话密钥?【参考方案2】:我有一个类似的问题,这就是为什么我开始悬赏这个问题。基本上,我有一个应用程序的面向公众的部分,它允许用户从一个表登录,而应用程序的一个管理部分允许管理员使用不同的表登录。我的 AppController 看起来像这样:
public $components = array(
'Session',
'Auth' => array(
'autoRedirect' => false,
'authenticate' => array(
'Form' => array(
'userModel' => 'User'
)
),
'loginAction' => array('controller' => 'users', 'action' => 'login'),
'loginRedirect' => array('controller' => 'users', 'action' => 'overview'),
'logoutRedirect' => array('controller' => 'users', 'action' => 'loggedout')
)
);
我有另一个 AdminController,我有这个:
public $components = array(
'Session',
'Auth' => array(
'authenticate' => array(
'CustomForm' => array(
'userModel' => 'Admin'
)
),
'loginAction' => array('controller' => 'admin', 'action' => 'login'),
'loginRedirect' => array('controller' => 'admin', 'action' => 'index'),
'logoutRedirect' => array('controller' => 'home', 'action' => 'index')
)
);
但正如在这个问题中提到的那样,两者的会话不会相处并相互覆盖。克服这个问题的最佳方法是什么?
【讨论】:
我很高兴你提出了赏金。在实现这一点时我也学到了一些额外的东西:在AppController
中设置Auth
的范围会产生多个登录的问题。 AppController
中的'scope' => array('User.delete_status' => 0)
未被CustomersController
中的'scope' => array('Customer.delete_status' => 0)
覆盖。相反,它被附加在 Cake 使用的 SQL 查询中,例如 .. WHERE User.delete_status=0 AND Customer.delete_status=0
。我不得不将那个位从 AppController 移到 UsersController 中(就像你在各自的控制器中有 Auth
一样)。【参考方案3】:
使用 MyDatabaseSession 之类的东西扩展 Model/Datasource/Session/DatabaseSession.php 会话处理程序并覆盖写入和读取方法。也许只需复制这两种方法的现有代码并添加类似
'app_id' => 配置::read('App.appId')
到 read() 条件并在 write 方法中执行相同操作。并且不要忘记将该字段添加到您的会话数据库架构和configure the session to use your handler。
<?php
App::uses('DatabaseSession', 'Model/Datasource/Session');
class ExtendedDatabaseSession extends DatabaseSession
public function read($id)
$row = $this->_model->find('first', array(
'conditions' => array(
'app_id' => Configure::read('App.appId'),
$this->_model->primaryKey => $id)));
if (empty($row[$this->_model->alias]['data']))
return false;
return $row[$this->_model->alias]['data'];
public function write($id, $data)
if (!$id)
return false;
$expires = time() + $this->_timeout;
$record = compact('id', 'data', 'expires');
$record[$this->_model->primaryKey] = $id;
$record['app_id'] = Configure::read('App.appId');
return $this->_model->save($record);
我不知道你的应用程序,所以你是否将应用程序 ID 写入配置数据取决于你,引导程序或 beforeFilter() 可能。我认为您应该在会话初始化之前添加它,否则您需要重新启动会话或其他东西。我把它留给你看正确的观点。 :)
【讨论】:
以上是关于具有两个模型会话的 Cakephp 身份验证组件的主要内容,如果未能解决你的问题,请参考以下文章
cakephp 一个表单,多个模型,不显示一个模型的验证消息