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