将控制器操作限制为Yii2中帖子的创建者

将控制器操作限制为Yii2中帖子的创建者,yii2,Yii2,有没有一种简单的方法可以在不使用完全RBAC的情况下将控制器操作限制为帖子的所有者/创建者 现在,我正在为每个控制器执行以下操作: public function actionUpdate( $id ) { $model = $this->findModel( $id ); if ( $model->user_id != Yii::$app->user->identity->id ) { throw new NotFoundHttpE

有没有一种简单的方法可以在不使用完全RBAC的情况下将控制器操作限制为帖子的所有者/创建者

现在,我正在为每个控制器执行以下操作:

public function actionUpdate( $id ) {
    $model = $this->findModel( $id );
    if ( $model->user_id != Yii::$app->user->identity->id ) {
        throw new NotFoundHttpException( 'The requested page does not exist.' );
    }
}
但我认为必须有更好的方法将某些控制器限制为创建正在编辑的
$model
的用户。

我们可以使用

访问控制过滤器

用于限制控制器操作而不是RBAC。如果只传递denyCallback,下面的代码将允许访问actionUpdate

use yii\filters\AccessControl;

class SiteController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'only' => ['update','delete'],
                'rules' => [
                    [
                        'actions' => ['update'],
                        'allow' => false,
                        'denyCallback' => function ($rule, $action) { //PHP callable that should be called when this rule will deny the access.
                            //Write your logic here to deny the action
                            throw new \Exception('You are not allowed to access this page');
                        }
                    ],
                ],
            ],
        ];
    }

    public function actionUpdate()
    {
        return $this->render('update');
    }
}
供您参考

1)建议使用RBAC和规则。这在专门的章节中有很好的介绍

检查作者id是否与通过参数传递的当前用户id匹配的规则示例:

namespace app\rbac;

use yii\rbac\Rule;

/**
 * Checks if authorID matches user passed via params
 */
class AuthorRule extends Rule
{
    public $name = 'isAuthor';

    /**
     * @param string|integer $user the user ID.
     * @param Item $item the role or permission that this rule is associated with
     * @param array $params parameters passed to ManagerInterface::checkAccess().
     * @return boolean a value indicating whether the rule permits the role or permission it is associated with.
     */
    public function execute($user, $item, $params)
    {
        return isset($params['post']) ? $params['post']->createdBy == $user : false;
    }
}
然后您需要将其与现有权限绑定(可以在迁移或扩展中完成):

然后,您可以检查用户是否可以像这样更新帖子:

use yii\web\ForbiddenHttpException;
use Yii;

public function actionUpdate($id)
{
    $model = $this->findModel($id);
    if (!Yii::$app->user->can('updatePost', ['post' => $model])) {
        throw new ForbiddenHttpException('You are not allowed to edit this post');
    }

    ...
}
还要注意,若您首先找到了模型,而用户无权编辑它,从逻辑上讲,最好抛出403禁止异常,而不是404,因为它已找到,但不允许编辑

不要忘记在
AccessControl
行为中包含这样的规则:

[
    'allow' => true,
    'actions' => ['update'],
    'roles' => ['@'],
],
这意味着此控制器的
update
操作只能由授权用户(不包括来宾)访问

2)如果出于某种原因您不想使用RBAC,您可以使用您的方法:

use yii\web\ForbiddenHttpException;

public function actionUpdate($id)
{
    $model = $this->findModel($id);
    if ($model->user_id != Yii::$app->user->id ) {
        throw new ForbiddenHttpException('You are not allowed to edit this post.');
    }

    ...
}
要改进这一点,您可以通过将此逻辑移动到帮助器方法来从此检查中提取:

namespace app\posts\components;

use Yii;

class PostPermission
{
    /**
     * @param $model Post
     * @return boolean
     */
    public static function allowedToUpdate($model)
    {
        return $model->user_id = Yii:$app->user->id;
    }
}
那就这样说吧:

use app\posts\components\PostPermission;
use yii\web\ForbiddenHttpException;

if (!PostPermission::allowedToUpdate($model) {
    throw new ForbiddenHttpException('You are not allowed to edit this post.');
}
这只是一个示例,方法不必是静态的,您可以使用
$model
构造实例

您可以直接在
Post
模型中创建方法,但最好不要用这种逻辑污染模型

3)我可以建议的另一种选择是,在查找模型时,最初将范围限制为当前用户:

use yii\web\NotFoundHttpException;

/**
 * @param integer $id
 * @return Post
 * @throws NotFoundHttpException
 */
protected function findModel($id)
{
    $model = Post::find(['id'=> $id, 'user_id' => Yii::$app->user->id])->one();
    if ($model) {
        return $model;
    } else {
        throw new NotFoundHttpException('This post does not exist.');
    }
}
这对于站点管理员来说是可以改进的:

use yii\web\NotFoundHttpException;

/**
 * @param integer $id
 * @return Post
 * @throws NotFoundHttpException
 */
protected function findModel($id)
{
    $query = Post::find()->where(['id' => $id]);
    if (!Yii::$app->user->is_admin) { // replace with your own check
        $query->andWhere(['user_id' => Yii::$app->user->id]);
    }
    $model = $query->one();
    if ($model) {
        return $model;
    } else {
        throw new NotFoundHttpException('This post does not exist.');
    }
}
那么你只写:

public function actionUpdate($id)
{
    $model = $this->findModel($id);
    ...
}

这样,在这两种情况下(模型未找到且当前用户不允许编辑),都会引发404未找到异常。从另一方面看,这并没有什么错,因为从技术上讲,对于这个用户来说,这个模型并不存在(因为他不是它的作者)。

我们需要先找到模型,然后执行检查,但访问控制在操作之前执行。或者我们可以复制代码来查找模型。另外,最好根据HTTP异常抛出,而不是泛型异常。感谢您提供如此详细的回答
public function actionUpdate($id)
{
    $model = $this->findModel($id);
    ...
}