Lewati ke isi

Integrasi API: Login & Penyimpanan Token


Tujuan Pembelajaran

Setelah mengikuti materi ini, siswa mampu: 1. Membuat model untuk respon Login (Token & User Data) menggunakan app.quicktype.io. 2. Menyimpan Token sesi menggunakan flutter_secure_storage. 3. Melakukan navigasi halaman menggunakan go_router. 4. Memahami alur autentikasi (Login -> Simpan Token -> Home).


Pertanyaan Pemantik

Setelah kita berhasil Register, bagaimana caranya aplikasi tahu kalau kita "sudah login" setiap kali kita membukanya?

Jawabannya adalah Token. Bayangkan token ini seperti "Tiket Masuk" atau stempel di tangan saat masuk wahana. Kita harus menyimpannya baik-baik agar tidak perlu login ulang terus-menerus.


1. Persiapan: Endpoint & Model

Kita akan membedah endpoint Login terlebih dahulu.

  • URL: {{ API_URL }}/login (Ambil dari .env)
  • Method: POST
  • Body:
    {
        "email": "contoh@gm.com",
        "password": "1234567890"
    }
    
  • Response Sukses (200 OK):
    {
        "token": "eyJhbGciOiJIUzI1NiIsIn...",
        "user": {
            "email": "contoh@gm.com",
            "id": 1,
            "name": "admin",
            "role": "admin"
        }
    }
    

Membuat Model AuthResponse

Response login kali ini mengandung objek yang kompleks. Kita akan buat modelnya otomatis.

  1. Copy JSON Response di atas.
  2. Buka app.quicktype.io.
  3. Set Name: AuthResponse.
  4. Set Language: Dart.
  5. Copy hasilnya.
  6. Buat file lib/models/auth_response_model.dart dan paste kodenya.

2. Instalasi Flutter Secure Storage

Kita tidak boleh menyimpan Token penting di sembarang tempat (seperti SharedPreferences biasa). Kita butuh tempat yang terenkripsi.

  1. Jalankan perintah di terminal:
    flutter pub add flutter_secure_storage
    
  2. (Khusus Android) Kita perlu mensetting minSdkVersion menjadi 18 atau lebih di android/app/build.gradle.

3. Update Auth Service

Kita akan update auth_service.dart untuk menambahkan fitur Login dan simpan token.

Buka lib/services/auth_service.dart dan tambahkan method login:

// Tambahkan import ini
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../models/auth_response_model.dart';

class AuthService {
  // ... kode lama (register) ...

  // Inisialisasi storage
  final storage = const FlutterSecureStorage();

  // Fungsi Login
  Future<bool> login({
    required String email, 
    required String password
  }) async {
    var url = Uri.parse('$baseUrl/login');

    var response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        "email": email,
        "password": password
      }),
    );

    if (response.statusCode == 200) {
      // 1. Ubah JSON jadi Object Model
      var data = authResponseFromJson(response.body);

      // 2. Simpan Token ke Secure Storage
      await storage.write(key: 'auth_token', value: data.token);

      // 3. (Opsional) Simpan data user jika perlu
      await storage.write(key: 'user_name', value: data.user.name);

      return true;
    } else {
      throw Exception('Login Gagal: Email atau Password salah!');
    }
  }
}

4. Integrasi ke Halaman Login

Sekarang kita hubungkan UI Login dengan Service baru ini.

Skenario: Jika Login berhasil -> Pindah ke Halaman Home (menggunakan go_router).

Buka lib/pages/login_page.dart:

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; // Import GoRouter
import '../services/auth_service.dart';

class LoginPage extends StatefulWidget {
  const LoginPage({super.key});

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final emailController = TextEditingController();
  final passwordController = TextEditingController();
  final AuthService authService = AuthService();
  bool isLoading = false;

  void login() async {
    setState(() { isLoading = true; });

    try {
      bool success = await authService.login(
        email: emailController.text,
        password: passwordController.text,
      );

      if (success) {
        if (!mounted) return; // Cek widget masih aktif

        // Navigasi ke Home menggunakan GoRouter
        context.go('/home'); // Sesuaikan dengan route path kalian

        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text("Login Berhasil!")),
        );
      }
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(e.toString())),
      );
    } finally {
      if (mounted) {
        setState(() { isLoading = false; });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Masuk Aplikasi")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(controller: emailController, decoration: const InputDecoration(labelText: "Email")),
            TextField(controller: passwordController, decoration: const InputDecoration(labelText: "Password"), obscureText: true),
            const SizedBox(height: 20),

            isLoading
              ? const CircularProgressIndicator()
              : ElevatedButton(
                  onPressed: login,
                  child: const Text("Masuk"),
                ),
          ],
        ),
      ),
    );
  }
}

Tugas Mandiri: Logout

Kalian sudah berhasil menyimpan token (Login). Sekarang tugas kalian adalah membuat fitur Logout.

Petunjuk: 1. Logout itu sederhana: Kita hanya perlu menghapus token yang tersimpan di flutter_secure_storage. 2. Jika token dihapus, aplikasi akan menganggap user belum login. 3. Cari tahu cara menghapus data di dokumentasi package flutter_secure_storage di pub.dev.

Tantangan: Buat tombol Logout di Halaman Home. Ketika ditekan: 1. Hapus token dari storage. 2. Lempar user kembali ke halaman Login (context.go('/login')).

Selamat mencoba!