Sprint 3, Week — 4: Implementasi fitur login dengan Django Oauth Toolkit + Unit testing

Django Oauth Toolkit merupakan sebuah framework authentication yang support OAuth2. Salah satu keunggulan Django Oauth Toolkit adalah sudah terintegrasi dengan Django Rest Framework, sehingga cocok dengan projek kami yang sudah terdapat API web service. Selain itu, implementasinya pun sangat mudah. Berikut adalah langkah — langkah konfigurasi/implementasi Django Oauth Toolkit pada project kami.

  • Install djago-oauth-toolkit dan django-corsheader-midleware
pip install django-oauth-toolkit django-cors-middleware
  • Tambahkan oauth2_provider and corsheaders pada installed apps di settings.py
INSTALLED_APPS = [
'fakultas',
'dgb',
'sdm',
'app',
'api',
'account',
'rest_framework',
'rest_framework_swagger',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'oauth2_provider',
'corsheaders',

]
  • Tambahkan Cors midleware
MIDDLEWARE = (
# ...
'corsheaders.middleware.CorsMiddleware',
# ...
)
  • Tambahkan routing untuk oauth dengan endpoind o/
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^fakultas/', include('fakultas.urls', namespace="fakultas")),
url(r'^dgb/', include('dgb.urls', namespace="dgb")),
url(r'^sdm/', include('sdm.urls', namespace="sdm")),
url(r'^app/', include('app.urls', namespace="app")),
url(r'^api/', include('api.urls', namespace="api")),
url(r'^accounts/', include('account.urls',
namespace='account')),
url(r'^o/', include(oauth2_endpoint_views, namespace="oauth2_provider")),
]

Perhatikan bahwa hanya terdapat endpoint accounts yang digunakan untuk login dan logout.

  • Konfigurasi Django Oauth Toolkit bisa dibilang sudah selesai, sekarang kita harus membuat suatu instance aplikasi yang digunakan untuk Authorization Server untuk login user. Caranya akses endpoint /o/applications/register. Akan muncul isian form sebagai berikut. Isi nama sesuai nama aplikasi yang diinginkan, lalu pilih client type dan authorization grant type implicit.
  • Implementasi fitur login dan logout

pada account app tambahkan endpoint login dan logout

urlpatterns = [
url(r'^login/', av.login, name='login'),
url(r'^logout/', logout, name='logout'),
]

login akan memanggil view function login pada views.py yang menggunakan LoginView dari django dan kita dapat menggunakan custom html sesuai kenginan kita.

from django.contrib.auth.views import LoginView


def login(req):
return LoginView.as_view(template_name='account/login.html')(req)

Sedangkan logout cukup panggil fungsi logout dari django.contrib.auth.views

  • Gunakan decorator login_required

Decorator login_required digunakan untuk membatasi view function, hal ini untuk memastikan user harus sudah login sebelum mengakses sebuah view. Jika belum login akan otomatis redirect ke halaman login. Kita dapat mengatur Login dan logout url pada settings.py sebagai berikut:

LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/accounts/login/'

Contoh penggunaan login required:

@login_required
def retrieve_cyd(req):
processed_applications = sdm_controller.get_processed_applications()
canceled_applications = sdm_controller.get_canceled_applications()
processed_applications_pagination = p.pagination(req, "processed_page", processed_applications)
canceled_applications_pagination = p.pagination(req, "canceled_page", canceled_applications)
.
.
.
.

sehingga ketika mengakses halaman utama sdm yaitu endpointnya adalah/sdm/view/cyd akan redirect ke halaman login dengan parameter next=/sdm/view/cyd yaitu halaman yang dituju setelah user berhasil login.

Unit testing oauth2

Berikut adalah contoh unit test untuk mengakses halaman utama sdm.

def setUp(self):
self.client = Client()
self.factory = RequestFactory()
self.user1 = User.objects.create_user('foo1', 'myemail@test.com1', 'bar1')
self.user2 = User.objects.create_user('foo2', 'myemail@test.com2', 'bar2')
self.user3 = User.objects.create_user('foo3', 'myemail@test.com3', 'bar3')
role_sdm = Role.objects.create(name="sdm")
role_fakultas = Role.objects.create(name="fakultas")
role_dgb = Role.objects.create(name="dgb")
fakultas = Faculty.objects.create(name='Teknik')
self.admin_sdm = Admin.objects.create(user_id=self.user1, nip=1, role=role_sdm, faculty=fakultas)
self.admin_fakultas = Admin.objects.create(user_id=self.user2, nip=2, role=role_fakultas, faculty=fakultas)
self.admin_dgb = Admin.objects.create(user_id=self.user3, nip=3, role=role_dgb, faculty=fakultas)
def test_sdm(self):
url = reverse("sdm:sdm_home")
self.client.login(username='foo2', password='bar2')
resp = self.client.get(url)
self.assertEqual(resp.url, '/accounts/login/?next=/sdm/view/cyd/')
self.client.login(username='foo1', password='bar1')
resp = self.client.get(url)
self.assertEqual(resp.status_code, 200)
self.assertTemplateUsed(resp, 'sdm/sdm_proses_pengajuan.html')

untuk melakukan authentikasi, dapat digunakan Client() untuk login. Perhatikan bahwa baris kedua pada fungsi test_sdm merupakan contoh login dengan user yang salah yaitu user foo2 meurupakan user dengan role fakultas, yang seharusnya adalah sdm. Sehingga url dari respon yang diperoleh harus url yang redirect ke halaman login ‘accounts/login/?next=/sdm/view/cyd/’. Lalu barus ke enam login dengan user yang benar, sehingga fungsi get paada client seharusnya berjalan dengan normal yaitu respp code nya 200, dan template yang digunakan adalah template sdm/sdm_proses_pengajuan.html

Referensi