Melanjutkan bahasan yang tertunda sebelumnya, kali ini kita akan bahas sedikit persiapan dan penggunaan fitur authorization.

Migrations

Pertama kita buat dulu Model dan migrations.

php artisan make:model -m Role

php artisan make:model -m Permission

Pada directory database/migrations akan ada dua file baru. Edit kedua file tersebut, lalu tambahkan name field. Kira-kira seperti ini pada method up()

// xxxx_xx_xx_xxxxxx_create_roles_table

Schema::create('roles', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->timestamps();
});

// xxxx_xx_xx_xxxxxx_create_permissions_table

Schema::create('permissions', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->timestamps();
});

Buat migrations baru untuk menghubungkan antara permissions dan roles, juga roles dan users

php artisan make:migration --create=permission_role create_permission_role_table

php artisan make:migration --create=role_user create_role_user_table

Edit kedua migrations tersebut

// xxxx_xx_xx_xxxxxx_create_permission_role_table

Schema::create('permission_role', function (Blueprint $table) {
    $table->unsignedInteger('permission_id');
    $table->unsignedInteger('role_id');

    $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');
    $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');

    $table->primary(['permission_id', 'role_id']);
});

// xxxx_xx_xx_xxxxxx_create_role_user_table

Schema::create('role_user', function (Blueprint $table) {
    $table->unsignedInteger('role_id');
    $table->unsignedInteger('user_id');

    $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

    $table->primary(['role_id', 'user_id']);
});

Model

Jika anda sudah pernah membaca artikel saya sebelumnya, ini tidak jauh berbeda. Tambahkan 4 method pada app/User.php

class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract {

    use Authenticatable, Authorizable, CanResetPassword;

    // ...

    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }

    public function hasRole($name)
    {
        foreach($this->roles as $role) {
            if ($role->name == $name) {
                return true;
            }
        }

        return false;
    }

    public function assignRole($role)
    {
        if (is_string($role)) {
            $role = Role::where('name', $role)->first();
        }

        return $this->roles()->attach($role);
    }

    public function revokeRole($role)
    {
        if (is_string($role)) {
            $role = Role::where('name', $role)->first();
        }

        return $this->roles()->detach($role);
    }

    // ...

}

Tambahkan beberapa method pada app/Role.php

class Role extends Model
{
    public function permissions()
    {
        return $this->belongsToMany(Permission::class);
    }

    public function users()
    {
        return $this->belongsToMany(User::class);
    }

    public function addPermission($permission)
    {
        if (is_string($permission)) {
            $permission = Permission::where('name', $permission)->first();
        }

        return $this->permissions()->attach($permission);
    }

    public function removePermission($permission)
    {
        if (is_string($permission)) {
            $permission = Permission::where('name', $permission)->first();
        }

        return $this->permissions()->detach($permission);
    }
}

Seeder

Tahap ini sebenarnya tidak harus. Tapi untuk mempermudah, kita buat seeder langsung di database/seeders/DatabaseSeeder.php. Jika anda lebih prefer seeder yang terpisah, anda bisa membuat dengan php artisan make:seeder

Tambahkan pada method run(), sehingga kira-kira menjadi seperti ini

public function run()
{
    // Basic roles data
    App\Role::insert([
        ['name' => 'admin'],
        ['name' => 'manager'],
        ['name' => 'editor'],
    ]);

    // Basic permissions data
    App\Permission::insert([
        ['name' => 'access.backend'],
        ['name' => 'create.user'],
        ['name' => 'edit.user'],
        ['name' => 'delete.user'],
        ['name' => 'create.article'],
        ['name' => 'edit.article'],
        ['name' => 'delete.article'],
    ]);

    // Add a permission to a role
    $role = App\Role::where('name', 'admin')->first();
    $role->addPermission('access.backend');
    $role->addPermission('create.user');
    $role->addPermission('edit.user');    
    $role->addPermission('delete.user');
    // ... Add other role permission if necessary

    // Create a user, and give roles
    $user = App\User::create([
        'email' => 'admin@example.com',
        'password' => bcrypt('anything_you_want'),
    ]);

    $user->assignRole('admin');

    // ... Add other user and assign them to roles
}

Jalankan migrations dan seeder

php artisan migrate --seed

AuthServiceProvider

Edit file app/Providers/AuthServiceProvider.php, tambahkan pada boot() method hingga kira-kira menjadi seperti ini

public function boot(GateContract $gate)
{
    $this->registerPolicies($gate);

    $permissions = App\Permission::all();

    foreach($permissions as $permission) {
        $gate->define($permission->name, function($user) use ($permission) {
            return $permission;
        });
    }
}

Usage

Sekarang kita bisa melakukan pengecekan permission/otoritasi dengan beberapa cara. Secara global kita bisa menggunakan Gate facade.

Route::get('/backend', function() {

    if (Gate::check('access.backend')) {
        return view('backend');
    }

    return abort(403);

});

Pada Controller kita bisa menggunakan Gate facade atau authorize method.

class UsersController extends Controller 
{
    public function create()
    {
        $this->authorize('create.user');
    }
}

Pada Model kita bisa menggunakan Gate facade atau can method.

class UsersController extends Controller 
{
    public function create()
    {
        if (auth()->user()->can('create.user')) {
            return view('users.create');
        }

        return abort(403);
    }
}

Pada View kita bisa menggunakan @can, sebagai contoh suatu menu hanya bisa dilihat oleh yang memiliki permission access.backend

// resources/views/welcome.blade.php

@can('access.backend')
  <a href="/backend">Go to backend</a>
@endcan

Conclusie

Pembuatan manual fitur otorisasi pada Laravel sebenarnya sangat mudah. Tapi dengan adanya fitur otorisasi bawaan, menjadikan proses pembuatan ini menjadi jauh lebih mudah.

Jika ada pertanyaan, ketidakjelasan, kebingungan, silahkan tanya pada kolom komentar. Source code menyusul! Source code bisa diakses di https://github.com/mul14/laravel-acl-demo-2

Artikel ini akan di-update karena dapat pencerahan lebih terang 😐

Iklan

31 pemikiran pada “NEW LARAVEL 5.1 ACL – PART #2

  1. Pada User model diatas ada variable $name itu dari mana ya om ?

    public function hasRole()
    {
    foreach($this->roles as $role) {
    if ($role->name == $name) {
    return true;
    }
    }

    return false;
    }

    Mungkin itu parameter di hasRole kah ?
    public function hasRole($name) { … }

  2. mau tanya untuk AuthServiceProvider nih om,

    di tutorial om mul kan ada code

    $permissions = \App\Permission::all();

    foreach($permissions as $permission) {
    $gate->define($permission->name, function($user) use ($permission) {
    return $permission;
    });
    }

    nah disini belum ada logic buat cek permissionnya yak om? :/ langsung return $permission aja, jadi asal Gate::check(‘nama_permission_benar_ada_di_db’) user mana aja returnnya true dong ya?

      1. Itu anonymous function atau closure yang ada sejak PHP 5.4. Digunakan untuk passing variable ke anonymous function.

        Misalnya

        $number = 3;
        
        $calc = function() {
            echo $number;
        };
        
        $calc();
        

        Code di atas akan error. Karena $number tidak dikenali di dalam closure. Tapi kalau ini bisa

        $number = 3;
        
        $calc = function() use ($number) {
            echo $number;
        };
        
        $calc();
        

        Detailnya silahkan pelajari di PHP Manual http://php.net/manual/en/functions.anonymous.php

  3. mas kok gak jalan ya, aku pakai scrip cari source code
    user admin hasrole admin permission access.backend

    @can(‘access.backend’)
    seharusnya setelah login menu ini yg tampil
    @else
    malah setelah login yg tampil yg disini
    @endcan

  4. Hallo om aku udah menyesuaikan dengan yang ada di github untuk file2
    app/User.php
    app/Role.php
    app/Permission.php
    Providers/AuthServiceProvider.php
    tetapi padasaat aku jalankan php artisan migrate –seed
    ada error : Class ‘App\Providers\Permission’ not Found

    aku menggunakan Laravel 5.2

    thanks 🙂

      1. om, hasManyThrough nya kenapa g jalan ya ?
        ane coba User::with(‘permissons’)->find(1);
        nknown column ‘roles.user_id’, kan memang g ada user_id di table roles ?
        mohon pencerahannya 😀

  5. Maaf oot, Masih bingung soal :

    foreach($permissions as $permission) {
        $gate->define($permission->name, function($user) use ($permission) {
            return $permission;
        });
    }

    variabel $user dicek dimana yah ?

Tinggalkan Balasan

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s