Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Authorization: the AccessControl filter

Authorization answers the question "what is this user allowed to do". Authentication found out who logged in; now you decide whether they may create and edit posts. The simplest tool is the AccessControl filter, which checks access before an action runs.

Where the filter is attached

The filter is attached in the behaviors() method of a controller. Add to controllers/PostController.php:

// controllers/PostController.php
use yii\filters\AccessControl;
 
public function behaviors(): array
{
    return [
        'access' => [
            'class' => AccessControl::class,
            'only' => ['create', 'update', 'delete'],
            'rules' => [
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
            ],
        ],
    ];
}

Log out and open /post/create: Yii redirects to the login page and brings you back after login. The list and the post page stay open: only lists the actions the filter applies to.

How rules are read

Rules are checked from top to bottom, and the first match wins. If none matches, access is denied.

Rule keyMeaning
allowtrue to allow, false to deny
roles@ is a logged-in user, ? is a guest, or a role name
actionsThe actions the rule applies to
verbsRequest methods, for example ['POST']
ipsVisitor addresses

Different rules for different actions

'rules' => [
    [
        'allow' => true,
        'actions' => ['index', 'view'],
        'roles' => ['?', '@'],
    ],
    [
        'allow' => true,
        'actions' => ['create', 'update', 'delete'],
        'roles' => ['@'],
    ],
],

Without the only key the filter applies to all actions of the controller: everyone may read posts, only logged-in users may change them. An action not mentioned in any rule is closed to everyone.

What the visitor sees

Yii redirects a guest to the login URL. It is set by a property of the user component in config/web.php:

// config/web.php
'user' => [
    'identityClass' => 'app\models\User',
    'loginUrl' => ['site/login'],
],

A logged-in user who is denied access gets the 403 "Forbidden" error.

Checking the owner

The filter does not know whose post is being opened. That only the author may edit a post is checked in the action itself:

use yii\web\ForbiddenHttpException;
 
public function actionUpdate(int $id)
{
    $post = Post::findOne($id);
 
    if ($post === null) {
        throw new NotFoundHttpException('Post not found.');
    }
 
    if ($post->user_id !== Yii::$app->user->id) {
        throw new ForbiddenHttpException('This is not your post.');
    }
 
    // loading the form and saving
}

Someone else's post at /post/update?id=7 cannot be edited: the page answers with a 403 error.

Buttons the visitor cannot use are hidden:

<?php
// views/post/view.php
 
use yii\helpers\Html;
?>
 
<?php if (!Yii::$app->user->isGuest && $post->user_id === Yii::$app->user->id): ?>
    <?= Html::a('Edit', ['post/update', 'id' => $post->id]) ?>
<?php endif; ?>

Only the author of the post sees the "Edit" link.

Common mistake

Hiding a link in a view does not close access. The URL /post/update?id=7 can be typed by hand, and without a check in the controller the action runs. The view manages convenience, while rights are checked by the filter and the action code.

Thanks for reading!

Donate to the site — we work hard for you.