codemix/accessrestrictable

A Yii ActiveRecordBehavior,它自动将访问限制条件应用于每个查询。

dev-master 2013-10-10 16:08 UTC

This package is auto-updated.

Last update: 2024-08-24 04:34:10 UTC


README

此行为为您的ActiveRecord查询添加了自动访问限制。

通过这种方式,它将一个新的安全层直接集成到模型中。如果任何用户尝试访问他没有权限的资源,查询结果将简单地为空。

安装

我们建议使用 composer 安装此扩展。将以下内容添加到您的 composer.json 文件的 require 部分

'codemix/accessrestrictable' : 'dev-master'

注意:目前还没有稳定版本。

您还需要在您的 index.php 文件顶部包含composer的自动加载器。

require_once __DIR__.'/protected/vendor/autoload.php';

请确保修复您的composer vendor 目录的路径。最后,您还需要在您的 main.php 中配置一个 alias

$vendor = realpath(__DIR__.'/../vendor');
return array(
    'alias' => array(
        'AccessRestrictable' => $vendor.'/codemix/AccessRestrictable/src/AccessRestrictable',
    ),
    ...

配置

要启用访问限制,您必须将此行为附加到一个ActiveRecord上,如下所示

<?php
class Post extends CActiveRecord
{
    public function behaviors()
    {
        return array(
            'restrictable' => array(
                'class'             => 'AccessRestrictable\Behavior',

                // Optional settings with default values
                // 'enableRestriction' => true
            ),
        );
    }

限制读取访问

为了限制对所有查询的 读取访问,您可以在您的记录中实现一个 beforeRead() 方法。它可以返回一个 boolean,以决定是否应用完全无限制(true)或完全限制访问(false)。

尽管更常见的用例是返回一个将应用于所有查询并限制结果集仅包含当前用户有权访问的记录的准则。为此,该方法可以返回一个 CDbCriteria 或一个包含准则参数的数组。

以下是一个示例

public function beforeRead()
{
    $user   = Yii::app()->user;
    $table  = $this->getTableAlias();

    if($user->checkAccess('admin')) {
        return true;    // no restriction for administrators
    } elseif($user->checkAccess('organizationAdmin')) {
        $userRecord = User::model()->findByPk(Yii::app()->user->id);

        // Admins in an organisation are allowed to see all users from that organisation
        return array(
            'condition' => "$table.organisation_id = :organisation",
            'params'    => array(':organisation' => $userRecord->organisation_id),
        );
    } else {
        // All other users can only query their own user record
        return array(
            'condition' => "$table.user_id = :id",
            'params'    => array(':id' => Yii::app()->user->id),
        );
    }
}

限制写入访问

为了限制对记录的 写入访问,您可以在您的记录中实现一个 beforeWrite() 方法。它将在任何插入、更新或删除操作之前被调用,并必须返回操作是否应该执行。

例如

public function beforeWrite()
{
    $user   = Yii::app()->user;

    if($user->checkAccess('admin')) {
        return true;    // admin can always write
    } elseif($user->checkAccess('organizationAdmin')) {
        $userRecord = User::model()->findByPk(Yii::app()->user->id);

        // Admins in an organisation are allowed to update all users from that organisation
        if($userRecord->organisation_id == $this->organisation_id) {
            return true;
        }
    } elseif($user->id==$this->id) {
        // All users can update their own user record
        return true;
    }

    // All others are denied
    return false;
}

用法

如果您已附加此行为,那么每次进行查询时,例如

<?php
$posts = Post::model()->findAll();

只有满足 beforeRead() 条件的记录才会返回。

同样,如果 beforeWrite() 返回 false,则任何 $post->save() 都会失败。

覆盖查询限制

如果您想要查询所有记录,例如,对于管理面板,您可能需要这样做。您可以使用 unrestricted() 范围来完成此操作

<?php
$posts = Post::model()->unrestricted()->findAll();

注意:如果您之前进行了另一个(受限)查询,则限制条件将应用于内部模型准则。要重置任何潜在的范围,您可以选择调用 resetScope() 或将 true 作为参数传递给 unrestricted()

覆盖写入限制

对于写入操作,您可以在写入之前调用 force() 方法。这将绕过 beforeWrite() 检查并始终保存记录。为了方便起见,它返回相同的记录,因此您可以轻松地链接调用

<?php
$post->force()->save();

注意:验证规则仍然适用。因此,如果您的记录有验证错误,即使您之前调用了 force(),记录也不会被保存。

禁用自动查询和写入限制

您还可以禁用自动访问限制,并且仅在显式请求时执行受限制的查询和写入。为此,您需要在行为配置中将 enableRestriction 设置为 false。

然后您可以通过命名范围应用限制查询条件

<?php
$posts = Post::model()->readable()->findAll();

对于写入操作,您将使用 writeable() 约束

<?php
$post->writeable()->save();

限制

由于ActiveRecord实现中的限制,以下方法使用时不会应用此行为的约束

  • deleteAll()
  • saveAttributes()
  • saveCounters()
  • findBySql()
  • findAllBySql()
  • countBySql()
  • exists()
  • 根据主键更新(updateByPk())
  • 更新全部(updateAll())
  • 更新计数器(updateCounters())
  • 根据主键删除(deleteByPk())
  • deleteAll()
  • 根据属性删除全部(deleteAllByAttributes())

我们建议避免使用上述方法,或者只有在您确信其影响时才使用它们。