My ArchLinux is back! \(^o^)/

Screen Shot 2016-01-31 at 10.04.41
Standar

Wohoo!! Akhirnya setelah sekian lama, saya bisa kembali menggunakan ArchLinux. Jadi ceritanya pada Q2-2015, laptop saya yang satunya mati karena colokan listriknya kecabut. Memang batre-nya juga udah soak sih. Masih bisa dihidupkan, tapi sayangnya hanya bisa masuk ke virtual console :'(

Untuk memperbaikinya sebenernya gampang kalau ada akses internet. Tapi sayangnya setiap ke cafe untuk mengakses internet, selalu diganggu dengan Captive Portal. Tanpa browser modern, gimanalah masukkin username dan password di Captive Portal? :/ Coba pake elinks atau lynx, ternyata ada Captive Portal pake JavaScript pula. Pake PhantomJS ternyata gak bisa juga :/ Atau salah caranya kali ya?

Cari tempat internet yang ada ethernet cable-nya susah banget :/ Main-main ke office temen juga nggak ada yang pake ethernet cable. Jadi yaa sudahlah. Toh saya masih bisa pake komputer-komputer yang lain.

Bulan Desember 2015 saya backup semua konfigurasi di /etc dengan git (gak pake etckeeper) dengan harapan suatu saat bisa install ArchLinux lagi. Untuk saat ini bolehlah pake yang distro yang installer-nya ada GUI. Lalu saya install Ubuntu 15.10. Instalasi berjalan normal. Tapi ntah kenapa setelah restart, Unity tidak muncul. Hanya background picture :'( Jadi tetep gak bisa dipake. Dan saya males ngutak-atik Ubuntu, ntah kenapa :/ Gak se-fun kalo ngutak-atik Arch atau Gentoo.

Nah, pada 30 Desember 2016 jam 11-an malam di salah satu coworking space yang sepi, saya liat ada kabel ethernet (kebetulan saya tidak Malam Mingguan seperti manusia lain pada umumnya :| #sh!t ). Langsung aja colok, boot dengan ArchLinux live, ping ke google, dan tadaa!! Ternyata bisa :D

Langsung sikat partisi yang dihuni oleh Ubuntu dengan mkfs.ext4 /dev/sda5. Lalu ikuti instruksi instalasi.

Jangan lupa juga ganti font di virtual console dengan setfont Lat2-Terminus16. Daftar font bisa diliat di /usr/share/kbd/consolefonts. Supaya jadi permanent, jangan lupa tambahkan FONT=Lat2-Terminus16 pada /etc/vconsole.conf

As VIM user, supaya lebih enak, ganti tombol Escape dengan Capslock. Caranya paling gampang copy dari /usr/share/kbd/keymaps/i386/dvorak/dvorak-programmer.map.gz ke /usr/local/share/kbd/keymaps/personal.map (jangan lupa gunzip). Lalu ubah Escape dan Capslock. Supaya permanent, tambahkan KEYMAP=/usr/local/share/kbd/keymaps/personal.map ke /etc/vconsole.conf

Setelah install beberapa package untuk network, baru bisa login ke Wifi dengan menggunakan wifi-menu atau nmtui (btw gambar di atas itu pake nmtui).

Mount partisi /home dan /opt, lalu generate ulang /etc/fstab dengan genfstab, reboot deh. :D

Lalu install package yang diperlukan seperti desktop environment, git, vim, emacs, steam, dll.

Fuahh… rasanya nikmat sekali bisa kembali menggunakan ArchLinux :D

Global Git Ignore

git-ignore-global
Standar

Dalam satu team, bisa jadi editor yang digunakan berbeda-beda. Ada yang menggunakan IDE seperti WebStorm, NetBeans, whatever. Dan saya sering jengkel dengan commit yang mengikutsertakan file-file yang tidak seharusnya di-commit.

Pada kasus WebStorm (atau JetBrains IDE lainnya), bisa jadi programmer mengikutsertakan folder .idea, atau nbproject pada NetBeans. Folder ini tidak seharusnya dimasukkan ke VCS (Versioning Control System).

Pengguna Windows juga sering mengikutsertakan file seperti Thumbs.db. Lain lagi dengan pengguna Mac OS X yang seringkali memasukkan .DS_Store ke VCS.

File-file tersebut tidak perlu dimasukkan ke VCS, dan tidak perlu juga dimasukkan ke .gitignore pada root project.

Yang paling membuat saya heran,

  • Apa mereka ini tidak melakukan review terlebih dahulu sebelum commit? :/
  • Bukannya kalau menggunakan fitur VCS di IDE (atau Git GUI) ada check list sebelum commit?
  • Apa semuanya langsung menggunakan git add . ?!?

Seharusnya sebelum melakukan commit, programmer melalukan review terlebih dahulu dengan git status. Pastikan yang masuk ke staging hanya file-file yang relevan dengan task yang dikerjakan.

Jika tidak sengaja memasukkan file yang tidak seharusnya, kan bisa remove dan commit ulang dengan menggunakan git commit --amend. :/

Solusi

Untuk kasus-kasus seperti ini, gunakanlah global git ignore. Ini sama dengan file .gitignore pada project anda, tapi berlaku secara global dan tidak perlu dimasukkan pada tiap project. Global yang dimaksud di sini dalam lingkup user, bukan system-wide.

Kita bisa cek global git ignore sudah di-set atau belum dengan perintah

git ignore --global

By default lokasi global git ignore ada di ~/.config/git/ignore. Cukup tambahkan pattern pada file tersebut, and done!

Untuk list yang biasa dimasukkan ke global git ignore, bisa anda cek di https://github.com/github/gitignore/tree/master/Global atau https://www.gitignore.io/

Untuk informasi lebih detail, silahkan periksa manual dengan man git-ignore dan man git-config, cek pada core.excludesFile.

Hufftt… malah jadi curhat -_-

Multiple Authentication di Laravel 5.2

laravel-framework
Standar

Pada kisah sebelumnya saya sebenarnya ingin mencari konfigurasi multiple authentication. Tapi malah nyasar ke token authentication.

Dengan multi-auth ini kita bisa membuat fitur login dengan table yang berbeda-beda dengan lebih mudah. Misalnya ada table dokter, pasien, dan staff.

Di Laravel 4, anda bisa menggunakan ollieread/multiauth untuk menggunakan multiple auth. Atau Kbwebs/MultiAuth untuk Laravel 5.0 dan 5.1.

Tetapi pada Laravel 5.2, Taylor Otwell menambahkan fitur ini ke core Laravel

So, gimana cara menggunakan multiple auth ini? Sangat mudah, tidak jauh berbeda dengan dua kisah sebelumnya. Kita bisa baca informasi pada config/auth.php

Screen Shot 2015-12-18 at 22.00.12

Jadi kita cukup menambahkan guards dan providers.

Persiapan

Contoh misalnya kita ingin ada tiga jenis user:

  • Doctor
  • Patient
  • Staff

Buat model yang mirip dengan app/User.php. Kita bisa copy dan edit nama class-nya. Jangan lupa buat juga  migrations untuk model tersebut. Isinya bisa copy dari /database/migrations/2014_10_12_000000_create_users_table.php, atau anda bisa buat sendiri sesuai dengan kebutuhan.

Setelah itu edit config/auth.php, tambahkan tiga guards dan tiga providers baru.

'guards' =>  [
    'doctor' =>  [
        'driver'   => 'session',
        'provider' => 'doctor',
    ],

    'patient' =>  [
        'driver'   => 'session',
        'provider' => 'patient',
    ],

    'staff' =>  [
        'driver'   => 'session',
        'provider' => 'staff',
    ],
],

// ... 

'providers' =>  [
    'doctor' =>  [
        'driver' => 'eloquent',
        'model'  => App\Doctor::class,
    ],

    'patient' =>  [
        'driver' => 'eloquent',
        'model'  => App\Patient::class,
    ],

    'staff' =>  [
        'driver' => 'eloquent',
        'model'  => App\Staff::class,
    ],
],

Login

Persiapan selesai. Saatnya simulasi untuk login. Eits, jangan lupa tambahkan user pada masing-masing model.

Berikut adalah file app/Http/routes.php

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

    $auth = auth()->guard('doctor'); // Atau \Auth::guard('doctor')

    $credentials = [
        'nip' =>  '04324321', // Nomor Induk Pegawai
        'password' =>  'sate',
    ];

    if ($auth->attempt($credentials)) {
        return 'Yay! Berhasil login (^o^)/';
    }

    return 'Gagal login.';

});

Well done :D

UPDATE 19 Jan 2016 23:33:56

Pada Laravel 5.2 terbaru, tepatnya 5.2.10, kita bisa gunakan

auth('doctor')

lebih singkat daripada

auth()->guard('doctor')

Detailnya bisa dilihat di https://github.com/laravel/framework/commit/2edaa2791317e1ff0cf80a5d8539e983154082c1.

Simple Token Authentication API di Laravel 5.2

laravel-framework
Standar

Setelah sebelumnya kita bahas cara menggunakan fitur baru di Laravel 5.2 yaitu autentikasi dengan token, sekarang kita bahas bagaimana cara menggunakannya bersamaan dengan metode autentikasi session.

Pada tulisan sebelumnya, by default kita mengubah konfigurasi “guard” yang default-nya adalah “web”¬†menjadi “api”. Sekarang kita coba menggunakan api guard tanpa mengubah konfigurasi default.

Contoh pada app/Http/routes.php

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

    if (auth()->check()) {
        return auth()->user();
    }

    abort(403, "You're not authorized to access this page.");
});

Route::get('api', function() {

    $auth = auth()->guard('api'); // Switch guard ke "api" driver

    if ($auth->check()) {
        return $auth->user();
    };

    abort(403, "You're not authorized to access this public REST API.");
});

Hmm, gimana kalau kita ubah menjadi middleware? Buat middleware baru dengan nama ApiAccess

./artisan make:middleware ApiAccess

Edit file app/Http/Middleware/ApiAccess.php

public function handle($request, Closure $next)
{
    $auth = auth()->guard('api');

    if ($auth->check()) {
        return $next($request);
    };

    abort(403, "You're not authorized to access this public REST API.");
}

Lalu tambahkan pada app/Http/Kernel.php

'auth.api' => \App\Http\Middleware\ApiAccess::class,

Karena sudah jadi middleware, sekarang kita lebih mudah menggunakannya. Misalnya pada app/Http/routes.php

$options = [
    'prefix' => 'api', 
    'namespace' => 'Api', 
    'middleware' => 'auth.api',
];

Route::group($options, function() {

    Route::get('/', 'UserController@index');

    Route::get('{user_id}', 'UserController@show');

});

Well done. Sekarang kita bisa menggunakan metode login seperti biasanya dan juga menggunakan metode autentikasi stateless dengan menggunakan token sederhana.

Validasi Token API di Laravel 5.2

laravel-framework
Standar

So, ceritanya saya lihat source code Laravel pada config/auth.php. Maksudnya sih mau melihat informasi tentang multiple auth. Itu lho, yang bisa menggunakan multiple table. Tapi ternyata malah menemukan hal baru :O

Screen Shot 2015-12-18 at 11.03.25

config/auth.php pada Laravel 5.2

Bisa dilihat ada metode autentikasi yang baru, yaitu token.

Karena penasaran, setelah Jumatan, saya langsung cari dimana code yang mengimplementasikan metode autentikasi ini. Dengan menggunakan command line fuzzy search pada terminal, saya langsung menemukan file yang dicari, yaitu Illuminate/Auth/TokenGuard.php.

Setelah baca-baca sedikit, akhirnya saya tau cara menggunakannya :D Sepertinya “saat ini” belum dibahas di dokumentasi resmi.

Cara Menggunakan

Pertama edit file users migrations. Tambahkan kolom api_token. Kira-kira menjadi seperti ini

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->string('email')->unique();
        $table->string('password', 60);

        $table->string('api_token')->unique(); // Kita tambahkan ini

        $table->rememberToken();
        $table->timestamps();
    });
}

Lalu lakukan migrasi database dengan ./artisan migrate.

Sekarang kita buat user baru dan api_token-nya. Terserah mau masukin dari artisan tinker, factory model, phpmyadmin, whatever.

Ubah metode autentikasi default pada config/auth.php dari web menjadi api

'defaults' => [
    'guard' => 'api', // Ubah ini
    'passwords' => 'users',
],

Sekarang pada file app/Http/routes.php, tambahkan ini

Route::get('/', function() {
    return auth()->user();
});

Ketika akses url /, tampilan akan kosong. Tapi ketika ditambahkan ?api_token=123 dengan asumsi api_token di database juga 123, maka akan muncul user tersebut.

Screen Shot 2015-12-18 at 13.52.48

PENTING!!!

Demi keamanan, jangan lupa masukkan api_token ke dalam hidden property yang ada di App/User.php, bersama dengan password dan remember_token.

Generate Dokumentasi Twitter Bootstrap v4

bootstra-banner
Standar

Twitter Bootstrap v4-alpha sudah rilis Agustus lalu. Kita bisa lihat dokumentasinya di http://v4-alpha.getbootstrap.com/. Saya sendiri sudah menggunakan versi development ini sejak rilis. Tapi sayangnya dokumentasi v4 ini tidak up-to-date. Beberapa CSS rule dari v3 telah dihilangkan. Misalnya .page-header. Dan ada juga yang berganti nama, seperti .img-responsive menjadi .img-fluid. Untuk mendapatkan dokumentasi yang lebih up-to-date, kita perlu generate dari source code di GitHub. Untuk download Bootstrap v4 keseluruhan, kita bisa menggunakan beberapa cara. Pilih salah satu yang anda suka.

git clone --depth=1 --branch=v4-dev https://github.com/twbs/bootstrap.git
  • menggunakan npm
npm install "twbs/bootstrap#v4-dev"

Setelah selesai download source code, kita perlu install semua npm dependencies, Grunt, Bundler.

  • Install Grunt

  • npm install -g grunt-cli
    
    • Install Bundler (jika belum punya)
    gem install bundler
    

    Jalankan bundler untuk install Jekyll

    bundler
    

    Sekarang jalankan

    grunt docs
    

    dan

    jekyll serve
    

    Lalu buka http://localhost:9091. Tadaa… dokumentasi terbaru siap dibaca-baca.

    bootstrap-v4-docs

    Kiri dokumentasi v4 di website, kanan adalah hasil generate dari source code.

    Bingung karena menggunakan Windows? :/
    Rasain!! ūüėā Makanya pake *nix aja berow!

    Referensi http://v4-alpha.getbootstrap.com/getting-started/build-tools/

    NEW LARAVEL 5.1 ACL ‚Äď PART #2

    laravel-framework
    Standar

    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 :|