我有两个主要表:
我正在寻找构建一个应用程序,其中User1登录并可以:
每个用户都可以访问某组图书。我不需要担任各种角色。
我为上面设置了MVC和关系(habtm)。我现在正在研究开发权限。你认为CakePHP ACL解决了这个问题还是过度杀伤?
如果它是矫枉过正的,是否有其他组件或更简单的方法来构建所需的功能?
答案 0 :(得分:1)
ACL是一个非常强大且灵活的系统 - 但它并不是免费的,它带来了复杂性。除非你有一个绝对需要细粒度权限的用例(你所描述的两个规则不适合这个) - 不要使用ACL。
此规则易于实施 - 例如添加到相关的查找呼叫:
$results = $BookModelInstance->find('all', array(
'conditions' => array(
'created_by' => AuthComponent::user('id')
)
));
此规则also easy to implement,稍微考虑一下:
$BookModelInstance->bindModel(array(
'hasOne' => array( // Yes, hasOne not hasMany
'MyPurchase' => array(
'className' => 'Purchase',
'foriegnKey' => 'user_id'
)
)
));
$results = $BookModelInstance->find('all', array(
'recursive' => 0, // to join hasOne+belongsTo associations into the query
'conditions' => array(
'MyPurchase.user_id' = AuthComponent::user('id'),
)
));
bindModel调用达到了SELECT .. FROM books LEFT JOIN book_users
的等价物。因此,查找调用中的条件会将结果限制为有购买图书的用户记录的图书。
自动应用这两个规则的简单实现是:
model Book extends AppModel {
public $actsAs = array('Containable');
public $restrictToUser = true;
public function beforeSave($options = array()) {
if (!$this->id) {
// Store who created this book
$this->data[$this->alias]['created_by'] = AuthComponent::user('id');
}
return true;
}
public function beforeFind($queryData) {
if (!$this->restrictToUser) {
// we don't want to apply user-level restrictions
return true;
}
$userId = AuthComponent::user('id');
if (!$userId) {
// we want to restrict to the current user - there isn't one.
return false;
}
// define the association to the purchase table
$this->bindModel(array(
'hasOne' => array(
'MyPurchase' => array(
'className' => 'Purchase',
'foriegnKey' => 'user_id'
)
)
));
//ensure the purchase table is included in the current query
$queryData['contain']['MyPurchase'] = array();
// restrict to rows created by the current user, OR purchased by the current user
$queryData['conditions']['OR'] = array(
$this->alias '.created_by' => $userId,
'MyPurchase.user_id' => $userId
);
return $queryData;
}
}
这要求字段created_by
(或等效字段)位于books表中,并使用containsable来确保purchases
表(或等效表)包含在所有相关查询中。
答案 1 :(得分:0)
最简单的解决方案:在控制器中添加条件,所以:
$this->set('books', $this->Book->find(
'all',
array('conditions' => array('Book.user_id' => $user['User']['id']))
);
缺点:您可能会在此处创建重复的代码,因为此检查也必须在其他地方进行。此外,当您开始测试模型时,您只能测试它返回书籍,您无法测试模型方法,如:getMyBooks($ userId)。所以不,不是首选的解决方案。
下一个解决方案:检入模型
可以通过签入例如您的书籍模型来完成。您可以检查afterfind()方法是否允许返回的记录。在您之前的查找中,您还可以为所有查询添加其他条件。
一般来说模型应该很胖所以我建议在那里实现清晰的方法:getAllBooks,getBooksOfUser($ User),getLatestBooksOfUser($ User)等。
为什么这是一个很好的实现?因为您现在可以在中心位置管理访问级别。您可以测试模型,但您确定它只返回该用户的书籍。
使用beforeSave等,你可以介入每次保存尝试并首先检查:嘿,你想保存这个,但这真的是你的书吗?
ACL解决方案
但总的来说,实现一些ACL解决方案(最好是内置的解决方案)可能是明智之举,因为这会使您的应用程序更具未来性。它允许灵活性,例如:
每个用户都可以访问某组图书。我不需要担任各种角色。
现在这是真的,但未来可以改变它。因此,如果您需要快速解决方案,只需自定义过滤记录。但想想未来。