Belajar Django - Authentication & User Management
Episode 10 of 27

Belajar Django - Authentication & User Management

Mengaktifkan sistem autentikasi Django: model User bawaan, alur login/logout, permissions & groups, serta implementasi RBAC. Membangun custom user model sebagai best practice sejak awal, lengkap dengan praktik login + role-based access control di blog devblog.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Form di episode 9 sudah menerima input, tetapi belum tahu siapa yang mengirim. Di episode ini kita menghidupkan Authentication & User Management: siapa pengguna, bagaimana mereka login, dan apa yang boleh mereka lakukan. Django menyediakan sistem auth lengkap di django.contrib.auth — model User, hashing password, session, permission, dan group.

Mengapa topik ini penting? Autentikasi adalah garis batas antara "sistem terbuka" dan "sistem yang bisa diandalkan". Instalasi auth Django yang benar menentukan kualitas keamanan seluruh aplikasi, dan keputusan custom user model yang diambil sekarang akan menentukan fleksibilitas sistem di masa depan.

Model User Bawaan

Django punya model User bawaan di django.contrib.auth dengan field esensial: username, password (selalu hash, tidak pernah plaintext), email, first_name, last_name, is_active, is_staff, is_superuser, plus relasi groups dan user_permissions.

Cek tabel auth
python manage.py shell -c "from django.contrib.auth.models import User; print(User.objects.first())"

Password disimpan sebagai hash dengan algoritma yang dapat di-upgrade (default PBKDF2, bisa diarahkan ke Argon2). Django tidak pernah menyimpan password asli — karena itu form reset password butuh alur tersendiri (episode 13 memakai email async).

Custom User Model: Keputusan Sejak Awal

Ini poin paling penting di episode ini: Django merekomendasikan custom user model sejak project pertama dibuat, bahkan jika tidak butuh field tambahan. Alasannya: mengganti AUTH_USER_MODEL setelah migrasi pertama adalah operasi sangat menyakitkan (episode 8 sudah kita singgung). Custom user model membuat penggantian nanti tinggal konfigurasi, bukan migrasi data.

Buat app accounts dan definisikan custom user:

Buat app accounts
python manage.py startapp accounts
Pythonaccounts/models.py - custom user
from django.contrib.auth.models import AbstractUser
from django.db import models
 
class User(AbstractUser):
    bio = models.TextField(blank=True)
    website = models.URLField(blank=True)
 
    def __str__(self):
        return self.username

Lalu beri tahu Django bahwa User di accounts adalah model auth:

Pythonsettings.py - AUTH_USER_MODEL
AUTH_USER_MODEL = "accounts.User"

Warning

AUTH_USER_MODEL hanya bisa diubah sebelum migrasi pertama dijalankan. Setelah database dibuat dengan user model default, mengganti model berarti operasi migrasi yang sangat kompleks. Untuk lab devblog, kita sudah beruntung karena belum ada migrasi auth yang diterapkan ke produksi — ubah sekarang sebelum terlambat.

Jangan lupa mendaftarkan admin custom user agar bisa dikelola dari panel episode 8:

Pythonaccounts/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
 
from .models import User
 
@admin.register(User)
class CustomUserAdmin(UserAdmin):
    fieldsets = UserAdmin.fieldsets + (
        ("Info Tambahan", {"fields": ("bio", "website")}),
    )

Login dan Logout

View login/logout bisa memakai bawaan Django atau versi custom. Untuk fleksibilitas, kita tulis sendiri dengan authenticate dan login:

Pythonaccounts/views.py
from django.contrib.auth import authenticate, login
from django.shortcuts import redirect, render
 
def login_view(request):
    if request.method == "POST":
        username = request.POST["username"]
        password = request.POST["password"]
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect("blog:home")
        return render(request, "accounts/login.html", {"error": "Kredensial salah."})
    return render(request, "accounts/login.html")

authenticate memverifikasi kredensial (dan menjalankan backend auth), login menulis session. Alur logout dengan method POST (bukan link GET) untuk mencegah CSRF logout:

Pythonaccounts/views.py - logout
from django.contrib.auth import logout
from django.shortcuts import redirect
 
def logout_view(request):
    if request.method == "POST":
        logout(request)
    return redirect("blog:home")

Tip

Selalu gunakan POST untuk aksi yang mengubah state (login/logout). Logout lewat link GET rawan CSRF — halaman jahat bisa memaksa browser korban logout. Django's LoginView/LogoutView bawaan sudah melakukan ini dengan benar; memakai versi bawaan adalah pilihan yang aman dan hemat waktu.

Untuk keperluan protection view, Django menyediakan decorator dan mixin:

PythonMembatasi akses
from django.contrib.auth.decorators import login_required
 
@login_required
def dashboard(request):
    return render(request, "accounts/dashboard.html")

@login_required mengalihkan user anonim ke halaman login dan mengembalikan mereka ke halaman tujuan setelah login (?next=). Di template, context processor auth dari episode 5 menyediakan {{ user }}:

Pythontemplate - user context
{% if user.is_authenticated %}
    <p>Halo, {{ user.username }}!</p>
    <form method="post" action="{% url 'accounts:logout' %}">
        {% csrf_token %}
        <button type="submit">Logout</button>
    </form>
{% else %}
    <a href="{% url 'accounts:login' %}">Login</a>
{% endif %}

Permissions & Groups

Django membedakan tiga level otoritas:

  1. is_superuser — akses penuh tak terbatas.
  2. is_staff — boleh masuk ke admin (/admin/).
  3. Permissions — izin spesifik per model/aksi, misalnya blog.can_publish_post.

Permission otomatis dibuat dari setiap model: add_, change_, delete_, view_. Cek di shell:

Lihat permission bawaan
python manage.py shell -c "from django.contrib.auth.models import Permission; print(list(Permission.objects.filter(codename__startswith='post')))"

Permissions diberikan langsung ke user atau — lebih rapi — dikelompokkan ke Group. Buat group dan assign lewat script:

Pythonaccounts/management/commands/setup_groups.py
from django.contrib.auth.models import Group, Permission
from django.core.management.base import BaseCommand
 
class Command(BaseCommand):
    help = "Buat group editor dan beri permission"
 
    def handle(self, *args, **options):
        editor, _ = Group.objects.get_or_create(name="editor")
        perms = Permission.objects.filter(content_type__app_label="blog")
        editor.permissions.set(perms)
        self.stdout.write(self.style.SUCCESS("Group editor siap."))

Pola "management command" ini bisa dijalankan di CI/provisioning (episode 23). Memberi permission per-group jauh lebih mudah dikelola daripada per-user saat tim bertumbuh.

RBAC di Views dan Templates

RBAC (Role-Based Access Control) menggabungkan permission + group. Cek di view:

Pythonblog/views.py - permission check
from django.contrib.auth.decorators import permission_required
 
@permission_required("blog.change_post", raise_exception=True)
def edit_post(request, pk):
    ...

raise_exception=True mengembalikan 403 (bukan redirect login) bagi user yang sudah login tapi tidak punya izin. Untuk cek permission di template, perms dari context processor episode 5:

Pythontemplate - cek permission
{% if perms.blog.change_post %}
    <a href="{% url 'blog:edit_post' post.pk %}">Edit</a>
{% endif %}

Di view yang memakai mixin CBV, kombinasikan LoginRequiredMixin + PermissionRequiredMixin:

Pythonblog/views.py - mixin CBV
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import UpdateView
 
class PostUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
    model = Post
    permission_required = "blog.change_post"
    template_name = "blog/post_form.html"

Perhatikan: permission model-level (change_post) belum membedakan siapa pemilik objek. Kontrol kepemilikan ("hanya author yang bisa edit post miliknya") disebut object-level permission dan kita implementasikan di episode 20.

Session dan Middleware Auth

Login menulis sessionid di cookie. Alurnya: SessionMiddleware (baca cookie → session data) → AuthenticationMiddleware (session → request.user). Inilah mengapa request.user selalu tersedia di view. Detail session — database, Redis, dan ekspirasi — kita bahas lengkap di episode 12, karena di sanalah performance auth ditentukan.

Penutup

Inti yang harus dibawa pulang:

  • Model User bawaan sudah lengkap (hash password, groups, permissions) — tetapi custom user model sejak awal menghindari migrasi menyakitkan nanti.
  • AUTH_USER_MODEL hanya bisa diganti sebelum migrasi pertama.
  • authenticate + login untuk masuk; POST untuk logout.
  • @login_required / @permission_required / mixin untuk membatasi view; perms di template.
  • Groups merapikan pemberian permission; management command men- seed group.
  • Permission model-level belum object-level — kita selesaikan di episode 20.

Di episode 11 selanjutnya kita menyajikan data blog sebagai API: Django REST Framework (DRF) — Serializers, ViewSets, Routers, autentikasi & permission, pagination, plus REST API CRUD lengkap dengan JWT SimpleJWT. Sampai jumpa di episode 11!

Belajar Django - Authentication & User Management | Belajar Django