0
0
0
share
#Python#django#rest#REST-API
0 Komentar
Membuat Aplikasi Web Realtime dengan Django, RabbitMQ dan Vue.js Bagian 2: Otentikasi dan Manajemen User
*Artikel ini merupakan terjemahan seri tutorial Real time Chat application built with Vue, Django, RabbitMQ and uWSGI WebSockets bagian kedua yang ditulis oleh Osaetin Daniel. *
Kita akan mulai pembuatan chatire dengan melakukan implementasi manajemen user dan otentikasi sehingga user bisa membuat akun baru dan melakukan login.
Berkat komunitas Django yang luar biasa, hal-hal tadi sudah tersedia untuk kita pakai. Oleh karena itu kita akan menggunakan pustaka django pihak ketiga bernama djoser
Mari kita pasang dari pypi
pip install djangorestframework
pip install djoser
Djoser adalah implementasi sistem otentikasi Django berbasis REST. Jadi dengan pustaka ini kita akan mendapatkan endpoint REST untuk melakukan registrasi user, pembuatan token, manajemen user dll.
Konfigurasi djoser
Kita mulai dengan konfigurasi palign sederhana untuk djoser. Tambahkan kode berikut di INSTALLED_APPS
INSTALLED_APPS = (
'django.contrib.auth',
...,
'rest_framework',
'rest_framework.authtoken',
'djoser',
)
lalu url djoser di urls.py
:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
...,
path('auth/', include('djoser.urls')),
path('auth/', include('djoser.urls.authtoken')),
]
Masukkan rest_framework.authentication.TokenAuthentication
ke dalam kelas otentikasi django rest:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
(...)
),
}
Terakhir, jalankan migrasi database dengan perintah python manage.py migrate
. Perintah ini akan membuat tabel-tabel yang dibutuhkan djsoer
.
Hanya dengan menambah kode-kode di atas sekarang endpoint otentikasi sudah siap. Mari kita buat user baru (jalankan di terminal):
curl -X POST http://127.0.0.1:8000/auth/users/create/ --data 'username=danidee&password=mypassword'
{"email":"","username":"danidee","id":1}
Voila! Sekarang kita sudah memiliki use baru. Lihat dokumentasi djoser untuk semua endpoint yang tersedia dan bagaimana cara menggunakannya di http://djoser.readthedocs.io/en/latest/base_endpoints.html
Vue.js
Vue adalah Framework JavaScript untuk membuat antarmuka yang Reactive. Meskipun penulis merupakan fans berat React (karena React-native), penulis lebih memilih Vue untuk membuat aplikasi web.
Salah satu alasannya ialah kurva belajar yang lebih bersahabat. Ia lebih mudah untuk mulai dipelajari dan tidak seperti React dimana kita harus bersusah payah menyiapkan banyak hal (dengan Webpack dan kawan-kawannya) untuk membuat aplikasi yang production ready. Pembaca cukup menulis tag <script>
seperti saat akan menggunakan JQuery
.
Ia juga memiliki komunitas yang giat dengan banyak plugin dan tutorial yang tersedia.
Kita akan memakai vue-cli
untuk membuat Vue app dengan cepat (tidak menggunakan tag <script>
). Methode ini memungkinkan kita untuk menggunakan ES6+
dan single file Vue component.
Pasang vue-cli
dari npm:
npm install -g vue-cli
Mari mulai proyek baru menggunakan webpack dengan vue-cli
vue init webpack chatire-frontend
**Catatan: Pastikan memilih opsi “install vue-router” **
Sekarang mungkin waktu yang tepat untuk membuat secangkir kopi atau mengambil snack karena prosesnya dapat memakan waktu lama tergantung kecepatan internet kita.
Selanjutnya, masuk ke direktori aplikasi vue yang sudah muncul (diterminal dengan perintah cd
) dan jalankan server development dengan perintah:
npm run dev
.
Seharusnya saat membuka alamat localhost:8080
di browser kita akan melihat:
Mari kita bahas sebentar struktur foldernya:
.
├── build
│ ├── build.js
│ ├── check-versions.js
│ ├── logo.png
│ ├── utils.js
│ ├── vue-loader.conf.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ └── webpack.prod.conf.js
├── config
│ ├── dev.env.js
│ ├── index.js
│ ├── prod.env.js
│ └── test.env.js
├── index.html
├── node_modules
├── package.json
├── package-lock.json
├── README.md
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ ├── main.js
│ └── router
│ └── index.js
├── static
└── test
├── e2e
│ ├── custom-assertions
│ │ └── elementCount.js
│ ├── nightwatch.conf.js
│ ├── runner.js
│ └── specs
│ └── test.js
└── unit
├── jest.conf.js
├── setup.js
└── specs
└── HelloWorld.spec.js
-
build: Direktori ini berisi skrips yang dipakai untuk menjalankan server development webpack atau bundel aplikasi saat siap dipakai di production. Contoh, perintah
npm run dev
sebetulnya memanggil perintah:webpack-dev-server --inline --progress --config build/webpack.dev.conf.js
Opsi
--inline
memasukkan file static yang di generate ke halamanindex.html
. -
config: Sesuai namanya, disini tempat menyimpan file-file yang berhubungan dengan konfigurasi development, testing dan production
-
src: Disini adalah tempat menulis sebagian besar kode-kode yang kita perlukan, ia memiliki subfolder yang yang memiliki fungsi masing-masing.
Component single file kita akan disimpan di folder ini. Akan ada satu component bawaan bernama
HelloWorld.vue
.File
index.js
di folder router memiliki konfigurasi untuk vue-router. -
static: File static (HTML, CSS and JavaScript) disimpan di folder ini.
-
test: Terakhir, template webpack dari
vue-cli
akan mempermudah ini jika ingin melakukan pengujian aplikasi dengan membuat End to end tests (e2e) di atas Nightwatch dan unit tests yang berjalan dengan Jest.Pengujian yang ada dapat dijalankan dengan perintah
npm run unit
(untuk unit tests) dannpm run e2e
untuk End to end tests.
vue-cli
juga menyiapkan fitur hotreloading untuk kita untuk membantu kita sehingga tidak perlu melakukan refresh di browser.
Konfigurasi Vue router
Buat dua component, satu untuk halaman utama bernama Chat.vue
dan satu lagi untuk User Authentication dan Signup bernama UserAuth.vue
Idealnya apa yang kita inginkan adalah menampilkan component berdasarkan status Login user. Jika User sudah melakukan Login, maka kita ingin menampilkan component Chat
jika tidak kita ingin menampilkan component UserAuth
.
Kita dapat melakukannya dengan menggunakan global navigation. Edit file router index.js
agar memiliki kode sebagai berikut:
import Vue from 'vue'
import Router from 'vue-router'
import Chat from '@/components/Chat'
import UserAuth from '@/components/UserAuth'
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/chats',
name: 'Chat',
component: Chat
},
{
path: '/auth',
name: 'UserAuth',
component: UserAuth
}
]
})
router.beforeEach((to, from, next) => {
if (sessionStorage.getItem('authToken') !== null || to.path === '/auth') {
next()
}
} else {
next('/auth')
}
})
export default router
Method beforeEach
dipanggil sebelum melakukan navigasi ke route manapun diaplikasi kita.
Jika sebuah token disimpan di dalam sessionStorage
kita akan memperbolehkan navigation melanjutkan pekerjaannya dengan memanggil next()
jika tidak kita kembali ke component auth.
Ke mana pun route yang dituju oleh user di aplikasi kita, fungsi ini akan memeriksa jika user memiliki auth token dan membawanya sesuai tujuan.
Halaman Login/Signup
Penulis sudah membuat halaman Login/Signup sederhana dengan Bootstrap 4. Berikut isi konten UserAuth.vue
:
<template>
<div class="container">
<h1 class="text-center">Welcome to Chatire!</h1>
<div id="auth-container" class="row">
<div class="col-sm-4 offset-sm-4">
<ul class="nav nav-tabs nav-justified" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="signup-tab" data-toggle="tab" href="#signup" role="tab" aria-controls="signup" aria-selected="true">Sign Up</a>
</li>
<li class="nav-item">
<a class="nav-link" id="signin-tab" data-toggle="tab" href="#signin" role="tab" aria-controls="signin" aria-selected="false">Sign In</a>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="signup" role="tabpanel" aria-labelledby="signin-tab">
<form @submit.prevent="signUp">
<div class="form-group">
<input v-model="email" type="email" class="form-control" id="email" placeholder="Email Address" required>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<input v-model="username" type="text" class="form-control" id="username" placeholder="Username" required>
</div>
<div class="form-group col-md-6">
<input v-model="password" type="password" class="form-control" id="password" placeholder="Password" required>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="toc" required>
<label class="form-check-label" for="gridCheck">
Accept terms and Conditions
</label>
</div>
</div>
<button type="submit" class="btn btn-block btn-primary">Sign up</button>
</form>
</div>
<div class="tab-pane fade" id="signin" role="tabpanel" aria-labelledby="signin-tab">
<form @submit.prevent="signIn">
<div class="form-group">
<input v-model="username" type="text" class="form-control" id="username" placeholder="Username" required>
</div>
<div class="form-group">
<input v-model="password" type="password" class="form-control" id="password" placeholder="Password" required>
</div>
<button type="submit" class="btn btn-block btn-primary">Sign in</button>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
const $ = window.jQuery // JQuery
export default {
data () {
return {
email: '', username: '', password: ''
}
}
}
</script>
<style scoped>
#auth-container {
margin-top: 50px;
}
.tab-content {
padding-top: 20px;
}
</style>
Pada sisipan kode di atas, v-model
dipakai untuk melakukan two way data binding untuk semua kolom input. Ini artinya apapun yang kita tulis di kolom tersebut dapat langsung diakses dari JavaScript menggunakan this.field_name
.
Kita juga membuat event listeners di kedua form menggunakan @submit.prevent
yang akan mendengarkan event form submitdari setiap form dan memanggil method yang diinginkan. Kita belum mengimplementasi method-method tersebut.
Karena kita menggunakan Bootstrap
, daripada memanggil jQuery
dari npm
kita menggunakan variabel $
untuk mendaftarkan window.jQuery
secara global.
Kita akan memakai method ajax jQuery
untuk berkomunikasi dengan server. Silahkan gunakan pustaka ajax lain seperti Axios jika tidak ingin menggunakan jQuery
. Pustaka ini cukup populer dikalangan pengguna Vue
.
Jangan lupa untuk menambahkan include file-file CSS dan JavaScript Bootstrap di halaman index.html
.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" integrity="sha384-Zug+QiDoJOrZ5t4lssLdxGhVrurbmBWopoEl+M6BdEfwnCJZtKxi1KgxUyJq13dy" crossorigin="anonymous">
<style>
.nav-tabs .nav-item.show .nav-link, .nav-tabs .nav-link.active {
outline: none;
}
</style>
<title>chatire-frontend</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/js/bootstrap.min.js" integrity="sha384-a5N7Y/aK3qNeh15eJKGWxsqtnX/wWdSZSKp+81YjTmS15nvnvxKHuzaWwXHDli+4" crossorigin="anonymous"></script>
</body>
</html>
Hasil yang didapat seharusnya:
Cukup oke kan?
Mari Kita Ambil auth token dari Django
Ktia ingin mendaftarkan user, memasukkannya dan membawanya ke route Chat.
Untuk melakukannya, kita harus mengimplement method signUp
dan signIn
di kode sebelumnya:
methods: {
signUp () {
$.post('http://localhost:8000/auth/users/create/', this.$data, (data) => {
alert("Your account has been created. You will be signed in automatically")
this.signIn()
})
.fail((response) => {
alert(response.responseText)
})
},
signIn () {
const credentials = {username: this.username, password: this.password}
$.post('http://localhost:8000/auth/token/create/', credentials, (data) => {
sessionStorage.setItem('authToken', data.auth_token)
sessionStorage.setItem('username', this.username)
this.$router.push('/chats')
})
.fail((response) => {
alert(response.responseText)
})
}
}
Sekarang coba submit form tadi. Oops! Ada kesalahan:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8000/auth/users/create. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
CORS
Menurut situs Mozilla:
Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to let a user agent gain permission to access selected resources from a server on a different origin (domain) than the site currently in use. A user agent makes a cross-origin HTTP request when it requests a resource from a different domain, protocol, or port than the one from which the current document originated.
Secara sederhana CORS memperbolehkan rikues Ajax dari domain tertentu untuk melakukan XmlHttpRequest
. Normalnya kita tidak bisa melakuakn XmlHttpRequest
dari situs dengan domain yang berbeda (catatan: jika ada yang salah harap dikoreksi).
Dalam kasus ini, meskipun sama-sama berjalan di localhost, karena berjalan di port yang berbeda (8080 dan 8000) mereka dianggap berada di domain yang berbeda.
Domain yang memiliki skema (http
atau https
), hostname (localhost
) dan port yang harus sama pula.
Jadi bagaimana cara menjalankan CORS di aplikasi django? Ada pustaka pihak ketiga untuk memudahkan hal tersebut bernama django-cors-headers
.
pip install django-cors-headers
tambahkan di INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Custom Apps
'rest_framework',
'rest_framework.authtoken',
'corsheaders',
'djoser'
]
tambahkan juga di (Pastikan ditulsi sebelum django.middleware.common.CommonMiddleware
)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
Terakhir atur CORS_ORIGIN_ALLOW_ALL = True
Catat bahwa apa yang kita lakukan mengaktifkan CORS untuk semua domain. Ini boleh dilakukan untuk development tapi saat di production kita mungkin hanya ingin domain tertentu saja
CORS_ORIGIN_WHITELIST
Baca dokumentasi django-cors-header untuk melihat opsi lain.
Setelah melakukannya, kita sekarang bisa membuat akun dan melakukan login.
Dibelakang layar, django-cors-headers
menggunakan sebuah Middleware untuk menambah header ke setiap rikues yang memberitahu Django bahwa rikues tersebut aman dan boleh dilakukan.
Logout
Karena kita memakai sessionStorage
untuk menyimpan auth token, kita bisa memulai session baru dengan membuka tab baru.
Jika ingin menyimpan token di tab baru atau saat browser di restart kita bisa memakai localStorage
. Ia memiliki API yang sama dengan sessionStorage
sehingga kita cukup mengganti session
ke local
.
Lalu kita dapat membuat sebuah fugnsi yang mengapus token dari storage dengan memanggil removeItem
. Berikut kode untuk melakukannya dengan localStorage
.
localStorage.removeItem('authToken')
Kesimpulan
Tutorial kali ini cukup sampai manajemen user dan sistem otensikasi. Kita mulai dengan memasang djoser, sebuah pustaka django yang memberikan endpoint REST
untuk otentikasi.
Kita juga menggunakan method ajax milik jQuery
untuk memanggil endpoints tersebut.
Selanjutnya kita membahas Same origin policy
sedikit dan belajar bagaimana memperbolehkan rikues Ajax dari aplikasi Vue ke backend Django menggunakan CORS
lewat django-cors-headers
.
Dibagian berikutnya, kita membuat model django dan API untuk aplikasi Chat.
0
0
0
share