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 key | Meaning |
|---|---|
allow | true to allow, false to deny |
roles | @ is a logged-in user, ? is a guest, or a role name |
actions | The actions the rule applies to |
verbs | Request methods, for example ['POST'] |
ips | Visitor 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.
Links in a view
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.