0 follower

Otentikasi dan Otorisasi

Otentikasi dan otorisasi diperlukan pada halaman Web yang dibatasi untuk para pengguna tertentu. Otentikasi adalah verifikasi apakah seseorang itu adalah orang yang berhak. Biasanya melibatkan username dan password, tapi dapat menyertakan metode lain yang menunjukan identitas, seperti kartu pintar, sidik jari, dll. Otorisasi adalah pencarian apakah orang yang sudah diidentifikasi (diotentikasi), diijinkan untuk memanipulasi sumber daya tertentu. Ini biasanya ditentukan dengan mencari apakah orang itu merupakan bagian dari aturan khusus yang memiliki akses ke sumber daya.

Yii memiliki kerangka kerja bawaan otentikasi/otorisasi yang mudah untuk dipakai dan dapat dikustomisasi untuk kebutuhan khusus.

Bagian utama dari kerangka kerja auth Yii adalah pra-deklarasi komponen aplikasi user, berupa obyek yang mengimplementasikan antar muka IWebUser. Komponen user mewakili informasi identitas bagi pengguna saat ini. Kita dapat mengaksesnya di mana saja menggunakan Yii::app()->user.

Memanfaatkan komponen user, kita dapat memeriksa apakah pengguna sudah masuk atau tidak via CWebUser::isGuest; kita bisa memasukan dan mengeluarkan seorang pengguna; kita bisa memeriksa apakah pengguna dapat melakukan operasi tertentu dengan memanggil CWebUser::checkAccess; dan kita juga bisa mendapatkan pembeda unik serta informasi identitas persisten lainnya mengenai pengguna.

1. Mendefinisikan Kelas Identitas

Untuk mengotentikasi seorang pengguna, kita mendefinisikan kelas identitas yang berisi logika otentikasi sebenarnya. Kelas identitas harus mengimplementasikan antar muka IUserIdentity. Kelas yang berbeda dapat diimplementasikan untuk pendekatan otentikasi yang berbeda (misalnya OpenID, LDAP). Awal yang baik adalah dengan memperluas CUserIdentity yang merupakan basis kelas untuk pendekatan otentikasi berdasarkan nama pengguna dan kata sandi.

Pekerjaan utama dalam mendefinisikan kelas identitas adalah implementasi metode IUserIdentity::authenticate. Kelas identitas juga dapat mendeklarasikan informasi identitas tambahan yang perlu tetap ada selama sesi pengguna.

Dalam contoh berikut, kita memvalidasi nama pengguna dan kata sandi terhadap tabel user dalam database menggunakan Rekaman Aktif. Kita juga menimpa metode getId guna mengembalikan variabel _id yang disetel saat otentikasi (implementasi standar akan menghasilkan nama pengguna sebagai ID). Saat otentikasi, kita menyimpan informasi title yang diambil dalam suatu kondisi nama yang sama dengan memanggil CBaseUserIdentity::setState.

class UserIdentity extends CUserIdentity
{
    private $_id;
    public function authenticate()
    {
        $record=User::model()->findByAttributes(array('username'=>$this->username));
        if($record===null)
            $this->errorCode=self::ERROR_USERNAME_INVALID;
        else if($record->password!==md5($this->password))
            $this->errorCode=self::ERROR_PASSWORD_INVALID;
        else
        {
            $this->_id=$record->id;
            $this->setState('title', $record->title);
            $this->errorCode=self::ERROR_NONE;
        }
        return !$this->errorCode;
    }
 
    public function getId()
    {
        return $this->_id;
    }
}

Informasi yang disimpan dalam sebuah keadaan (dengan memanggil CBaseUserIdentity::setState) akan dialihkan ke CWebUser yang menyimpannya dalam penyimpanan persisten, seperti misalnya sesi. Informasi ini dapat diakses seperti properti CWebUser. Sebagai contoh, kita bisa mendapatkan informasi title dari pengguna saat ini dengan Yii::app()->user->title (Ini sudah tersedia sejak versi 1.0.3. Pada versi sebelumnya, kita harus menggunakan Yii::app()->user->getState('title').)

Info: Secara standar, CWebUser menggunakan sesi sebagai penyimpanan persisten atas informasi identitas pengguna. Jika login berbasis-cookie dihidupkan (dengan menyetel CWebUser::allowAutoLogin menjadi true), informasi identitas pengguna juga dapat disimpan dalam cookie. Pastikan Anda tidak mendeklarasikan informasi sensitif (misalnya kata sandi) menjadi persisten.

2. Masuk dan Keluar

Menggunakan kelas identitas dan komponen pengguna, kita dapat mengimplementasikan aksi login dan logout dengan mudah.

// Masukkan pengguna dengan username dan password yang disediakan.
$identity=new UserIdentity($username,$password);
if($identity->authenticate())
    Yii::app()->user->login($identity);
else
    echo $identity->errorMessage;
......
// Keluarkan pengguna saat ini
Yii::app()->user->logout();

Distandarkan, seorang pengguna akan dikeluarkan setelah periode waktu tertentu bila tidak aktif, tergantung pada konfigurasi sesi. Untuk mengubah perilaku ini, kita dapat menyetel properti allowAutoLogin pada komponen pengguna menjadi true dan mengoper parameter durasi ke dalam metode CWebUser::login. Selanjutnya pengguna akan tetap masuk selama durasi yang sudah ditetapkan, meskipun jika dia menutup jendela browser. Catatan bahwa fitur ini mengharuskan browser pengguna untuk menerima cookie.

// Biarkan pengguna tetap masuk selama 7 hari.
// Pastikan allowAutoLogin disetel true pada komponen user.
Yii::app()->user->login($identity,3600*24*7);

3. Filter Kontrol Akses

Filter kontrol akses merupakan skema awal otorisasi yang memeriksa apakah pengguna saat ini dapat melakukan aksi kontroler yang diminta. Otorisasi didasarkan pada nama pengguna, alamat IP klien dan jenis permintaan. Ini disediakan sebagai filter bernama "accessControl".

Tip: Filter kontrol akses cukup untuk skenario sederhana. Untuk kontrol akses yang kompleks, Anda dapat menggunakan role-based access (RBAC) yang akan segera dibahas.

Untuk mengontrol akses terhadap aksi dalam kontroler, kita menginstalasi filter kontrol akses dengan menimpa CController::filters (lihat Filter untuk lebih jelasnya mengenai instalasi filter).

class PostController extends CController
{
    ......
    public function filters()
    {
        return array(
            'accessControl',
        );
    }
}

Dalam contoh di atas, kita menetapkan bahwa filter kontrol akses harus diterapkan pada setiap aksi PostController. Rincian aturan otorisasi yang dipakai oleh filter ditetapkan dengan menimpa CController::accessRules pada kelas kontroler.

class PostController extends CController
{
    ......
    public function accessRules()
    {
        return array(
            array('deny',
                'actions'=>array('create', 'edit'),
                'users'=>array('?'),
            ),
            array('allow',
                'actions'=>array('delete'),
                'roles'=>array('admin'),
            ),
            array('deny',
                'actions'=>array('delete'),
                'users'=>array('*'),
            ),
        );
    }
}

Kode di atas menetapkan tiga aturan, masing-masing disajikan sebagai array. Elemen pertama array bisa berupa 'allow' atau 'deny' dan pasangan nama-nilai lainnya menetapkan parameter pola aturan. Aturan-aturan ini membaca: aksi create dan edit tidak bisa dijalankan oleh pengguna anonim; aksi delete dapat dijalankan oleh pengguna dengan aturan admin; dan aksi delete tidak bisa dijalankan oleh siapapun.

Aturan akses dievaluasi satu demi satu sesuai urutan yang ditetapkan. Aturan pertama yang sesuai dengan pola saat ini (misalnya nama pengguna, roles, alamat IP klien) menentukan hasil otorisasi. Jika aturan ini adalah aturan allow, aksi bisa dijalankan; jika aturan deny, aksi tidak bisa dijalankan; jika tidak ada aturan yang sesuai konteks, aksi masih bisa dijalankan.

Tip: Untuk memastikan aksi tidak bisa dijalankan pada konteks tertentu, sangat bermanfaat untuk selalu menetapkan semuanya sesuai aturan deny di akhir set aturan, seperti yang berikut:

return array(
    // ... aturan lain...
    // aturan ini menolak aksi 'delete' untuk semua konteks
    array('deny',
        'action'=>'delete',
    ),
);

Alasan atas aturan ini dikarenakan jika tidak ada seorangpun yang sesuai konteks aturan, aksi akan dijalankan.

Aturan akses akan sesuai dengan parameter konteks berikut:

  • aksi: menetapkan aksi mana dijalankan jika aturan sesuai. Ini harus berupa array ID aksi. Pembandingannya sensitif jenis huruf.

  • kontroler: menetapkan kontroler mana yang sesuai aturan ini. Ini harus berupa array ID kontroler. Pembandingannya sensitif jenis huruf. Opsi ini sudah tersedia sejak versi 1.0.4.

  • pengguna: menetapkan pengguna mana yang sesuai aturan ini. Nama pengguna saat ini dipakai untuk penyesuaian. Pembandingannya sensitif jenis huruf. Tiga karakter khusus dapat dipakai di sini:

    • *: setiap pengguna, termasuk anonim dan pengguna terotentikasi.
    • ?: pengguna anonim.
    • @: pengguna terotentikasi.
  • roles: menetapkan roles mana yang sesuai aturan ini. Pemakaian fitur kontrol akses berbasis-role dijelaskan pada subseksi berikutnya. Aturan diterapkan khususnya jika CWebUser::checkAccess mengembalikan true pada salah satu set aturan. Catatan, Anda harus menggunakan set aturan terutama dalam aturan allow karena secara definisi, aturan mewakili perijinan untuk melakukan sesuatu.

  • ip: menetapkan alamat IP klien mana yang sesuai aturan ini.

  • verb: menetapkan jenis permintaan apa (misalnya GET, POST) sesuai aturan ini. Pembandingannya tidak sensitif jenis huruf.

  • ekspresi: menetapkan ekspresi PHP yang nilainya menunjukan apakah aturan ini sesuai atau tidak. Dalam ekspresi, Anda dapat menggunakan variabel $user yang merujuk ke Yii::app()->user. Opsi ini sudah tersedia sejak versi 1.0.3.

Menangani Hasil Otorisasi

Ketika otorisasi gagal, misalnya, pengguna tidak diijinkan untuk melakukan aksi yang ditetapkan, salah satu dari dua skenario berikut mungkin terjadi:

  • Jika pengguna tidak masuk dan jika properti loginUrl komponen pengguna dikonfigurasi menjadi URL halaman login, browser akan mengalihkan ke halaman itu.

  • Sebaliknya eksepsi HTTP akan ditampilkan dengan kode kesalahan 401.

Ketika mengkonfigurasi properti loginUrl, Anda dapat menyediakan URL relatif ataupun absolut. Selain itu, Anda juga bisa menyediakan array yang akan dipakai untuk membuat URL dengan memanggil CWebApplication::createUrl. Elemen pertma array harus menetapkan rute ke aksi kontroler login, dan pasangan nama-nilai lainnya adalah parmeter GET. Sebagai contoh,

array(
    ......
    'components'=>array(
        'user'=>array(
            // this is actually the default value
            'loginUrl'=>array('site/login'),
        ),
    ),
)

Jika browser dialihkan ke halaman login dan login berhasil, kita mungkin ingin mengalihkan browser kembali ke halaman yang menyebabkan kegagalan otorisasi. Bagaimana kita mengetahui URL halaman itu? Kita bisa memperoleh informasi ini dari properti returnUrl pada komponen pengguna. Selanjutnya kita dapat melakukan pengalihan berikut:

Yii::app()->request->redirect(Yii::app()->user->returnUrl);

4. Kontrol Akses Berbasis-Role

Role-Based Access Control (RBAC) menyediakan kontrol akses terpusat yang sederhana dan bertenaga. Silahkan merujuk ke artikel Wiki untuk lebih jelasnya mengenai perbandingan RBAC dengan skema kontrol akses tradisional.

Yii mengimplementasikan skema RBAC hirarkis via komponen aplikasi authManager. Berikut ini, pertama kami perkenalkan konsep utama yang dipakai dalam skema ini; kemudian kami jelaskan bagaimana untuk mendefinisikan data otorisasi; di akhir kami perlihatkan bagaimana menggunakan data otorisasi untuk melakukan pemeriksaan akses.

Tinjauan

Konsep dasar dalam RBAC Yii adalah item otorisasi. Item otorisasi adalah perijinan untuk melakukan sesuatu (misalnya membuat tulisan blog baru, mengatur pengguna). Berdasarkan granularitas dan pengguna yang ditargetkan, item otorisasi bisa diklasifikasikan sebagai operasi, tugas dan roles. Role terdiri dari tugas, tugas terdiri dari operasi, dan operasi adalah perijinan yang atomis. Sebagai contoh, kita bisa memiliki sistem dengan role administrator yang terdiri dari tugas post management dan tugas user management. Tugas user management terdiri dari operasi create user, update user dan delete user. Agar lebih fleksibel, Yii juga mengijinkan role terdiri dari role atau operasi lain, tugas terdiri dari tugas lain, dan operasi terdiri dari operasi lainnya.

Item otorisasi secara unik diidentifikasi dengan namanya.

Item otorisasi dapat dikaitkan dengan aturan bisnis. Aturan bisnis adalah bagian kode PHP yang akan dijalankan saat melakukan pemeriksaan akses terhadap itemnya. Hanya ketika eksekusi mengembalikan nilai true, pengguna akan dipertimbangkan memiliki perijinan yang disajikan oleh item. Sebagai contoh, saat mendifinisikan operasi updatePost, kita akan menambahkan aturan bisnis yang memeriksa apakah ID pengguna sama seperti ID pemuat tulisan agar pembuat tersebut dapat memiliki perijinan untuk memutakhirkan tulisan.

Menggunakan item otorisasi, kida bisa membangun hirarki otorisasi. Item A adalah leluhur dari item B lain dalam hirarki jika A terdiri dari B (atau katakanlah A mewarisi perijinan disajikan oleh B). Item dapat memiliki multipel item anak, dan juga bisa memiliki multipel item leluhur. Oleh karena itu, hirarki otorisasi adalah grarik urutan-bagian daripada sebuah pohon (susunan). Dalam hirarki ini, item role berada tingkat atas, item operasi pada tingkat bawah, item tugas berada diantaranya.

Setelah kita memiliki hirarki otorisasi, kita bisa menempatkan roles dalam hirarki ini ke pengguna aplikasi. Pengguna setelah ditempatkan akan memiliki perijinan yang disajikan oleh role. Sebagai contoh, jika kita menempatkan role administrator kepada seorang pengguna, dia akan memiliki perijinan administrator yang termasuk post management dan user management (dan operasi terkait seperti misalnya create user).

Sekarang bagian yang menyenangkan. Dalam aksi kontroler, kita ingin memeriksa apakah pengguna saat ini dapat menghapus tulisan yang ditetapkan. Menggunakan hirarki RBAC serta penempatan, ini bisa dikerjakan dengan mudah seperti berikut:

if(Yii::app()->user->checkAccess('deletePost'))
{
    // hapus tulisan
}

Mengkonfigurasi Manajer Otorisasi

Sebelum kita mendefinisikan hirarki otorisasi dan melakukan pemeriksaan akses, kita perlu mengkonfigurasi komponen aplikasi authManager. Yii menyediakan dua jenis manajer otorisasi: CPhpAuthManager dan CDbAuthManager. Yang pertama menggunakan file naskah PHP untuk menyimpan data otorisasi, sementara yang kedua menyimpan data otorisasi dalam database. Ketika kita mengkonfigurasi komponen aplikasi authManager, kita harus menetapkan kelas komponen mana yang dipakai dan apa nilai awal untuk komponennya. Sebagai contoh,

return array(
    'components'=>array(
        'db'=>array(
            'class'=>'CDbConnection',
            'connectionString'=>'sqlite:path/to/file.db',
        ),
        'authManager'=>array(
            'class'=>'CDbAuthManager',
            'connectionID'=>'db',
        ),
    ),
);

Selanjutnya kita dapat mengakses komponen aplikasi authManager menggunakan Yii::app()->authManager.

Mendefinisikan Hirarki Otorisasi

Mendefinisikan hirarki otorisasi mencakup tiga langkah: mendefinisikan item otorisasi, membuat hubungan diantara item otorisasi, dan menempatkan role ke pengguna aplikasi. Komponen aplikasi authManager menyediakan seluruh set API untuk tugas-tugas ini.

Untuk mendefinisikan item otorisasi, panggil salah satu metode berikut, tergantung pada jenis itemnya:

Setelah kita memiliki satu set item otorisasi, kita dapat memanggil metode untuk membuat hubungan diantara item-item otorisasi:

Dan terakhir, kita memanggil metode berikut untuk menempatkan item role ke pengguna individual:

Di bawah ini kami memperlihatkan contoh mengenai pembangunan hirarki otorisasi dengan API yang sudah disediakan:

$auth=Yii::app()->authManager;
 
$auth->createOperation('createPost','create a post');
$auth->createOperation('readPost','read a post');
$auth->createOperation('updatePost','update a post');
$auth->createOperation('deletePost','delete a post');
 
$bizRule='return Yii::app()->user->id==$params["post"]->authID;';
$task=$auth->createTask('updateOwnPost','update a post by author himself',$bizRule);
$task->addChild('updatePost');
 
$role=$auth->createRole('reader');
$role->addChild('readPost');
 
$role=$auth->createRole('author');
$role->addChild('reader');
$role->addChild('createPost');
$role->addChild('updateOwnPost');
 
$role=$auth->createRole('editor');
$role->addChild('reader');
$role->addChild('updatePost');
 
$role=$auth->createRole('admin');
$role->addChild('editor');
$role->addChild('author');
$role->addChild('deletePost');
 
$auth->assign('reader','readerA');
$auth->assign('author','authorB');
$auth->assign('editor','editorC');
$auth->assign('admin','adminD');

Info: sementara pada contoh di atas terlihat panjang dan membosankan, ini dikarenakan untuk keperluan demonstratif saja. Para pengembang biasanya harus mengembangkan beberapa antar muka agar pengguna akhir bisa menggunakan hirarki otorisasi lebih intuitif.

Menggunakan Aturan Bisnis

Ketika kita mendefinisikan hirarki otorisasi, kita dapat mengaitkan sebuah role, tugas atau operasi dengan apa yang disebut aturan bisnis. Kita juga dapat mengaitkan aturan bisnis saat kita menempatkan sebuah role kepada pengguna. Aturan bisnis adalah bagian dari kode PHP (teppatnya pernyataan PHP) yang dijalankan ketika kita melakukan pemeriksaan akses. Nilai kode yang dikembalikan dipakai untuk menentukan apakah role atau penempatan diterapkan pada pengguna saat ini. Dalam contoh di atas, kita mengaitkan aturan bisnis dengan tugas updateOwnPost. Dalam aturan bisnis, kita cukup memeriksa apakah ID pengguna saat ini sama dengan ID pembuat tulisan. Informasi tulisan dalam array $params disediakan oleh para pengembang saat melakukan pemeriksaan akses.

Pemeriksaan Akses

Untuk melakukan pemeriksaan akses, pertama kita perlu mengetahui nama item otorisasi. Sebagai contoh, untuk memeriksa apakah pengguna saat ini dapat membuat sebuah tulisan, kita akan memeriksa apakah dia memiliki perijinan yang disiapkan oleh operasi createPost. Kemudian kita memanggil CWebUser::checkAccess untuk melakukan pemeriksaan akses:

if(Yii::app()->user->checkAccess('createPost'))
{
    // buat tulisan
}

Jika aturan otorisasi dikaitkan dengan aturan bisnis yang memerlukan parameter tambahan, kita juga dapat mengoperkannya. Contoh, untuk memeriksa apakah pengguna dapat memutakhirkan sebuah tulisan, kita akan melakukan

$params=array('post'=>$post);
if(Yii::app()->user->checkAccess('updateOwnPost',$params))
{
    // mutakhirkan tulisan
}

Menggunakan Role Standar

Catatan: Fitur standar role sudah tersedia sejak versi 1.0.3

Banyak aplikasi Web memerlukan beberapa role sangat khusus yang ditempatkan ke setiap pengguna atau hampir semua pengguna sistem. Sebagai contoh, kita mungkin ingin menemppatkan beberapa hak bagi para pengguna terotentikasi. Ini akan memunculkan banyak masalah pemeliharaan jika kita secara eksplisit menetapkan dan menyimpan penempatan role tersebut. Kita dapat mengeksploitasi role standar guna memecahkan masalah ini.

Role standar adalah sebuah role yang secara implisit ditempatkan ke setiap pengguna, termasuk yang terotentikasi dan pengunjung. Kita tidak ingin secara eksplisit menempatkannya kepada pengguna. Saat CWebUser::checkAccess dipanggil, role standar akan diperiksa lebih dulu seolah-olah ditempatkan kepada pengguna.

Role standar harus dideklarasikan dalam properti CAuthManager::defaultRoles. Contohnya, konfigurasi berikut mendeklarasikan dua role sebagai role standar: authenticated dan guest.

return array(
    'components'=>array(
        'authManager'=>array(
            'class'=>'CDbAuthManager',
            'defaultRoles'=>array('authenticated', 'guest'),
        ),
    ),
);

Karena role standar ditempatkan ke setiap pengguna, biasanya perlu dikaitkan dengan aturan bisnis yang menentukan apakah role benar-benar diterapkan kepada pengguna. Sebagai contoh, kode berikut mendefinisikan dua role, authenticated dan guest, yang secara efektif diterapkan masing-masing ke para pengguna terotentikasi dan pengunjung.

$bizRule='return !Yii::app()->user->isGuest;';
$auth->createRole('authenticated', 'authenticated user', $bizRule);
 
$bizRule='return Yii::app()->user->isGuest;';
$auth->createRole('guest', 'guest user', $bizRule);