Belajar Yii - Auth & RBAC
Episode 9 of 27

Belajar Yii - Auth & RBAC

Membangun autentikasi dan otorisasi di Yii: login dan signup dengan password hashing yang benar lewat Security component, komponen yii\web\User dengan IdentityInterface, access control filter per action, serta RBAC berbasis DbManager untuk memetakan role, permission, dan assignment pengguna.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Aplikasi yang tidak bisa membedakan siapa penggunanya tidak bisa membedakan hak aksesnya. Di episode 9 ini kita membangun dua lapisan keamanan yang saling terkait: autentikasi (membuktikan siapa kalian) dan otorisasi (apa yang boleh kalian lakukan).

Yii menyediakan keduanya sebagai komponen built-in: yii\web\User untuk menangani login/session, dan RBAC (Role-Based Access Control) untuk memetakan hak akses. Di episode ini kita implementasikan login, signup, hashing password yang benar, lalu membangun sistem role admin + permission yang bisa langsung dipakai di aplikasi enterprise.

Identitas Pengguna: IdentityInterface

Yii tidak mengunci model user tertentu — ia hanya butuh class yang mengimplementasikan yii\web\IdentityInterface. Inilah kontrak yang menghubungkan yii\web\User dengan data kalian (bisa tabel users, API eksternal, atau LDAP):

models/User.php - IdentityInterface
<?php
 
namespace app\models;
 
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
 
class User extends ActiveRecord implements IdentityInterface
{
    public static function tableName(): string
    {
        return 'users';
    }
 
    public static function findIdentity($id): ?User
    {
        return static::findOne($id);
    }
 
    public static function findIdentityByAccessToken($token, $type = null): ?User
    {
        return static::findOne(['access_token' => $token]);
    }
 
    public function getId(): int
    {
        return $this->id;
    }
 
    public function getAuthKey(): ?string
    {
        return $this->auth_key;
    }
 
    public function validateAuthKey($authKey): bool
    {
        return $this->auth_key === $authKey;
    }
}

Empat method ini adalah kontraknya: findIdentity (muat user dari session), findIdentityByAccessToken (dipakai API di episode 10), getAuthKey/validateAuthKey (validasi "remember me" via cookie). Kolom auth_key di tabel users menyimpan string acak — bukan password.

Login dan Signup

Password Hashing yang Benar

Jangan pernah menyimpan password mentah atau hash dengan MD5/SHA1. Yii menyediakan Security component yang membungkus password_hash() dengan algoritma bcrypt (secara default):

Hashing dan verifikasi password
use Yii;
 
// saat signup atau ganti password
$user->password_hash = Yii::$app->security->generatePasswordHash($password);
 
// saat login
if (!Yii::$app->security->validatePassword($password, $user->password_hash)) {
    // password salah
}

generatePasswordHash menghasilkan string yang berisi salt + cost + hash sekaligus, jadi tidak perlu menyimpan salt terpisah. Validasi password selalu lewat fungsi ini agar tahan timing attack.

LoginForm dan actionLogin

Template basic sudah menyediakan LoginForm — mari kita periksa logikanya:

models/LoginForm.php
<?php
 
namespace app\models;
 
use Yii;
use yii\base\Model;
 
class LoginForm extends Model
{
    public $username;
    public $password;
    public $rememberMe = true;
 
    private ?User $_user = null;
 
    public function rules(): array
    {
        return [
            [['username', 'password'], 'required'],
            ['rememberMe', 'boolean'],
            ['password', 'validatePassword'],
        ];
    }
 
    public function validatePassword($attribute, $params): void
    {
        if (!$this->hasErrors()) {
            $user = $this->getUser();
            if (!$user || !$user->validatePassword($this->password)) {
                $this->addError($attribute, 'Username atau password salah.');
            }
        }
    }
 
    public function login(): bool
    {
        if (!$this->validate()) {
            return false;
        }
        return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
    }
 
    private function getUser(): ?User
    {
        if ($this->_user === null) {
            $this->_user = User::findByUsername($this->username);
        }
        return $this->_user;
    }
}

Yii::$app->user->login() menulis identitas ke session (dan cookie remember me jika durasi diisi). Di controller:

controllers/SiteController.php - actionLogin
public function actionLogin()
{
    if (!Yii::$app->user->isGuest) {
        return $this->goHome();
    }
 
    $model = new LoginForm();
    if ($model->load(Yii::$app->request->post()) && $model->login()) {
        return $this->goBack();
    }
 
    $model->password = '';
    return $this->render('login', ['model' => $model]);
}

Signup

Pola signup sama: SignupForm mengumpulkan input, menghasilkan User baru, dan langsung login:

models/SignupForm.php
public function signup(): ?User
{
    if (!$this->validate()) {
        return null;
    }
 
    $user = new User();
    $user->username = $this->username;
    $user->email = $this->email;
    $user->setPassword($this->password);       // generatePasswordHash
    $user->generateAuthKey();                  // string acak untuk remember me
    $user->status = User::STATUS_ACTIVE;
 
    return $user->save() ? $user : null;
}

Access Control Filter

Lapisan pertama otorisasi: yii\filters\AccessControl di controller membatasi akses per action berdasarkan role:

controllers/PostController.php - AccessControl
use yii\filters\AccessControl;
 
public function behaviors(): array
{
    return [
        'access' => [
            'class' => AccessControl::class,
            'rules' => [
                [
                    'allow' => true,
                    'actions' => ['index', 'view'],
                    'roles' => ['?'],   // guest (belum login)
                ],
                [
                    'allow' => true,
                    'actions' => ['create', 'update', 'delete'],
                    'roles' => ['@'],   // sudah login
                ],
                [
                    'allow' => true,
                    'actions' => ['delete'],
                    'roles' => ['admin'],
                ],
                [
                    'allow' => false,
                ],
            ],
        ],
    ];
}

Makna simbol role: ? = guest, @ = semua user yang login, nama role lain (misal admin) = role RBAC. Aturan dievaluasi dari atas ke bawah — aturan pertama yang cocok menentukan hasil.

RBAC: Role-Based Access Control

AccessControl saja cukup untuk app kecil, tapi untuk aplikasi enterprise kalian butuh RBAC: pemetaan role → permission → assignment user yang disimpan di database. Yii menyediakan yii\rbac\DbManager.

1. Buat Tabel RBAC

Buat tabel RBAC di database
php yii migrate/up --migrationPath=@yii/rbac/migrations

Perintah ini membuat 4 tabel: auth_assignment, auth_item, auth_item_child, auth_rule.

2. Daftarkan DbManager

config/web.php dan console.php - authManager
'components' => [
    'authManager' => [
        'class' => 'yii\rbac\DbManager',
    ],
],

Jangan lupa mendaftarkan juga di config/console.php — konsol butuh authManager saat kita menulis perintah untuk seeding role.

3. Seeding Role dan Permission

RBAC memisahkan role (misal admin, editor) dan permission (misal createPost, deletePost). Cara terbaik membuatnya adalah lewat console command yang idempotent — bisa dijalankan berulang:

commands/RbacController.php
<?php
 
namespace app\commands;
 
use Yii;
use yii\console\Controller;
 
class RbacController extends Controller
{
    public function actionInit(): int
    {
        $auth = Yii::$app->authManager;
 
        // permissions
        $createPost = $auth->createPermission('createPost');
        $createPost->description = 'Membuat post baru';
        $auth->add($createPost);
 
        $updatePost = $auth->createPermission('updatePost');
        $updatePost->description = 'Mengubah post';
        $auth->add($updatePost);
 
        $deletePost = $auth->createPermission('deletePost');
        $deletePost->description = 'Menghapus post';
        $auth->add($deletePost);
 
        // roles
        $editor = $auth->createRole('editor');
        $auth->add($editor);
        $auth->addChild($editor, $createPost);
        $auth->addChild($editor, $updatePost);
 
        $admin = $auth->createRole('admin');
        $auth->add($admin);
        $auth->addChild($admin, $editor);
        $auth->addChild($admin, $deletePost);
 
        $this->stdout("RBAC selesai diinisialisasi\n");
        return self::EXIT_CODE_NORMAL;
    }
 
    public function actionAssign(string $username, string $role): int
    {
        $auth = Yii::$app->authManager;
        $user = \app\models\User::findByUsername($username);
 
        if (!$user) {
            $this->stderr("User tidak ditemukan: $username\n");
            return self::EXIT_CODE_ERROR;
        }
 
        $auth->assign($auth->getRole($role), $user->id);
        $this->stdout("Role '$role' ditugaskan ke $username\n");
        return self::EXIT_CODE_NORMAL;
    }
}

Perhatikan struktur hierarki: admin adalah anak dari editor (lewat addChild), jadi admin mewarisi semua permission editor ditambah deletePost. Hierarki inilah yang membuat RBAC skala besar tetap mudah dikelola.

Inisialisasi dan assignment
php yii rbac/init
php yii rbac/assign admin admin-role

4. Cek Permission di Kode

Di controller atau view, cek hak akses dengan can():

Cek permission
use Yii;
 
if (!Yii::$app->user->can('deletePost')) {
    throw new ForbiddenHttpException('Tidak punya akses.');
}
 
// di view: tampilkan tombol hanya jika berhak
<?php if (Yii::$app->user->can('updatePost')): ?>
    <a href="<?= Url::to(['post/update', 'id' => $model->id]) ?>">Edit</a>
<?php endif; ?>

Dan di AccessControl, nama role/permission bisa langsung dipakai:

AccessControl dengan permission
[
    'allow' => true,
    'actions' => ['delete'],
    'roles' => ['deletePost'],  // permission, bukan role
],

Important

Bedakan kedua istilah: permission = kemampuan atomik ("dapat menghapus post"), role = kumpulan permission + hierarki ("editor", "admin"). Berikan role kepada user; berikan permission kepada role. Jangan menugaskan permission langsung ke user — hierarki akan kacau saat tim membesar.

Praktik: Admin Role Lengkap

Sekarang satukan semuanya: tabel user sudah ada, RBAC aktif, role sudah di-seed. Verifikasi alurnya:

Verifikasi RBAC
php yii migrate/up --migrationPath=@yii/rbac/migrations --interactive=0
php yii rbac/init
php yii rbac/assign budi admin

Lalu di PostController, tambahkan aturan RBAC agar hanya admin yang bisa menghapus. Login sebagai user tanpa role — tombol delete tidak muncul dan akses langsung ditolak 403. Login sebagai budi — semuanya berfungsi.

Penutup

Inti yang harus dibawa pulang:

  • IdentityInterface adalah kontrak antara yii\web\User dan data user kalian.
  • Password wajib di-hash dengan Security::generatePasswordHash (bcrypt) — jangan pernah mentah.
  • AccessControl memfilter akses per action dengan role ?, @, atau nama role RBAC.
  • RBAC dengan DbManager: permission atomik, role hierarkis, assignment via konsol.
  • Yii::$app->user->can('permission') dipakai untuk cek akses di kode dan view.

Di episode 10 selanjutnya, kita membangun sisi lain aplikasi: REST API & Behaviorsyii\rest\ActiveController yang menghasilkan endpoint CRUD JSON secara otomatis, serializers, autentikasi token, rate limiting, serta behaviors seperti timestamp, soft delete, dan blameable yang menempel ke siklus hidup model. Sampai jumpa di episode 10!