Basics

Autentikasi

Pengantar

Nylo Website v7 menyediakan sistem autentikasi komprehensif melalui kelas Auth. Sistem ini menangani penyimpanan kredensial pengguna secara aman, manajemen sesi, dan mendukung beberapa sesi bernama untuk konteks auth yang berbeda.

Data auth disimpan secara aman dan disinkronkan ke Backpack (penyimpanan key-value dalam memori) untuk akses sinkron yang cepat di seluruh aplikasi Anda.

import 'package:nylo_framework/nylo_framework.dart';

// Authenticate a user
await Auth.authenticate(data: {"token": "abc123", "userId": 1});

// Check if authenticated
bool loggedIn = await Auth.isAuthenticated(); // true

// Get auth data
dynamic token = Auth.data(field: 'token'); // "abc123"

// Logout
await Auth.logout();

Mengautentikasi Pengguna

Gunakan Auth.authenticate() untuk menyimpan data sesi pengguna:

// With a Map
await Auth.authenticate(data: {
  "token": "ey2sdm...",
  "userId": 123,
  "email": "user@example.com",
});

// With a Model class
User user = User(id: 123, email: "user@example.com", token: "ey2sdm...");
await Auth.authenticate(data: user);

// Without data (stores a timestamp)
await Auth.authenticate();

Contoh Dunia Nyata

class _LoginPageState extends NyPage<LoginPage> {

  Future<void> handleLogin(String email, String password) async {
    // 1. Call your API to authenticate
    User? user = await api<AuthApiService>((request) => request.login(
      email: email,
      password: password,
    ));

    if (user == null) {
      showToastDanger(description: "Invalid credentials");
      return;
    }

    // 2. Store the authenticated user
    await Auth.authenticate(data: user);

    // 3. Navigate to home
    routeTo(HomePage.path, removeUntil: (_) => false);
  }
}

Mengambil Data Auth

Ambil data auth yang tersimpan menggunakan Auth.data():

// Get all auth data
dynamic userData = Auth.data();
print(userData); // {"token": "ey2sdm...", "userId": 123}

// Get a specific field
String? token = Auth.data(field: 'token');
int? userId = Auth.data(field: 'userId');

Method Auth.data() membaca dari Backpack (penyimpanan key-value dalam memori Nylo Website) untuk akses sinkron yang cepat. Data secara otomatis disinkronkan ke Backpack saat Anda mengautentikasi.

Memperbarui Data Auth

Nylo Website v7 memperkenalkan Auth.set() untuk memperbarui data auth:

// Update a specific field
await Auth.set((data) {
  data['token'] = 'new_token_value';
  return data;
});

// Add new fields
await Auth.set((data) {
  data['refreshToken'] = 'refresh_abc123';
  data['lastLogin'] = DateTime.now().toIso8601String();
  return data;
});

// Replace entire data
await Auth.set((data) => {
  'token': newToken,
  'userId': userId,
});

Logout

Hapus pengguna yang terautentikasi dengan Auth.logout():

Future<void> handleLogout() async {
  await Auth.logout();

  // Navigate to login page
  routeTo(LoginPage.path, removeUntil: (_) => false);
}

Logout dari Semua Sesi

Saat menggunakan beberapa sesi, hapus semuanya:

// Logout from default and all named sessions
await Auth.logoutAll(sessions: ['device', 'admin']);

Memeriksa Autentikasi

Periksa apakah pengguna saat ini terautentikasi:

bool isLoggedIn = await Auth.isAuthenticated();

if (isLoggedIn) {
  // User is authenticated
  routeTo(HomePage.path);
} else {
  // User needs to login
  routeTo(LoginPage.path);
}

Sesi Ganda

Nylo Website v7 mendukung beberapa sesi auth bernama untuk konteks yang berbeda. Ini berguna ketika Anda perlu melacak berbagai jenis autentikasi secara terpisah (misalnya, login pengguna vs registrasi perangkat vs akses admin).

// Default user session
await Auth.authenticate(data: user);

// Device authentication session
await Auth.authenticate(
  data: {"deviceToken": "abc123"},
  session: 'device',
);

// Admin session
await Auth.authenticate(
  data: adminUser,
  session: 'admin',
);

Membaca dari Sesi Bernama

// Default session
dynamic userData = Auth.data();
String? userToken = Auth.data(field: 'token');

// Device session
dynamic deviceData = Auth.data(session: 'device');
String? deviceToken = Auth.data(field: 'deviceToken', session: 'device');

// Admin session
dynamic adminData = Auth.data(session: 'admin');

Logout Berdasarkan Sesi

// Logout from default session only
await Auth.logout();

// Logout from device session only
await Auth.logout(session: 'device');

// Logout from all sessions
await Auth.logoutAll(sessions: ['device', 'admin']);

Memeriksa Autentikasi per Sesi

bool userLoggedIn = await Auth.isAuthenticated();
bool deviceRegistered = await Auth.isAuthenticated(session: 'device');
bool isAdmin = await Auth.isAuthenticated(session: 'admin');

ID Perangkat

Nylo Website v7 menyediakan identifier perangkat unik yang bertahan antar sesi aplikasi:

String deviceId = await Auth.deviceId();
// Example: "550e8400-e29b-41d4-a716-446655440000-1704067200000"

ID perangkat:

  • Dibuat sekali dan disimpan secara permanen
  • Unik untuk setiap perangkat/instalasi
  • Berguna untuk registrasi perangkat, analitik, atau push notification
// Example: Register device with backend
Future<void> registerDevice() async {
  String deviceId = await Auth.deviceId();
  String? pushToken = await FirebaseMessaging.instance.getToken();

  await api<DeviceApiService>((request) => request.register(
    deviceId: deviceId,
    pushToken: pushToken,
  ));

  // Store device auth
  await Auth.authenticate(
    data: {"deviceId": deviceId, "pushToken": pushToken},
    session: 'device',
  );
}

Sinkronisasi ke Backpack

Data auth secara otomatis disinkronkan ke Backpack saat Anda mengautentikasi. Untuk sinkronisasi manual (misalnya saat boot aplikasi):

// Sync default session
await Auth.syncToBackpack();

// Sync specific session
await Auth.syncToBackpack(session: 'device');

// Sync all sessions
await Auth.syncAllToBackpack(sessions: ['device', 'admin']);

Ini berguna dalam urutan boot aplikasi Anda untuk memastikan data auth tersedia di Backpack untuk akses sinkron yang cepat.

Rute Awal

Rute awal adalah halaman pertama yang dilihat pengguna saat membuka aplikasi Anda. Atur menggunakan .initialRoute() di router Anda:

// routes/router.dart
appRouter() => nyRoutes((router) {
  router.add(LoginPage.path).initialRoute();

  router.add(HomePage.path);
});

Anda juga dapat mengatur rute awal bersyarat menggunakan parameter when:

appRouter() => nyRoutes((router) {
  router.add(OnboardingPage.path).initialRoute(
    when: () => !hasCompletedOnboarding()
  );

  router.add(HomePage.path).initialRoute(
    when: () => hasCompletedOnboarding()
  );
});

Navigasi kembali ke rute awal dari mana saja menggunakan routeToInitial():

void _goHome() {
  routeToInitial();
}

Rute Terautentikasi

Rute terautentikasi menggantikan rute awal saat pengguna sudah login. Atur menggunakan .authenticatedRoute():

appRouter() => nyRoutes((router) {
  router.add(LoginPage.path).initialRoute();

  router.add(HomePage.path).authenticatedRoute();

  router.add(ProfilePage.path);
  router.add(SettingsPage.path);
});

Saat aplikasi boot:

  • Auth.isAuthenticated() mengembalikan true → pengguna melihat rute terautentikasi (HomePage)
  • Auth.isAuthenticated() mengembalikan false → pengguna melihat rute awal (LoginPage)

Anda juga dapat mengatur rute terautentikasi bersyarat:

router.add(HomePage.path).authenticatedRoute(
  when: () => hasCompletedSetup()
);

Navigasi ke rute terautentikasi secara programatis menggunakan routeToAuthenticatedRoute():

// After login
await Auth.authenticate(data: user);
routeToAuthenticatedRoute();

Lihat juga: Router untuk dokumentasi routing lengkap termasuk guard dan deep linking.

Rute Preview

Selama pengembangan, Anda mungkin ingin dengan cepat melihat pratinjau halaman tertentu tanpa mengubah rute awal atau terautentikasi Anda. Gunakan .previewRoute():

appRouter() => nyRoutes((router) {
  router.add(LoginPage.path).initialRoute();

  router.add(HomePage.path).authenticatedRoute();

  router.add(SettingsPage.path).previewRoute(); // Opens first during development
});

previewRoute() menggantikan keduanya initialRoute() dan authenticatedRoute(), membuat rute yang ditentukan menjadi halaman pertama yang ditampilkan terlepas dari status auth.

Peringatan: Hapus .previewRoute() sebelum merilis aplikasi Anda.

Rute Tidak Dikenal

Tentukan halaman fallback untuk saat pengguna menavigasi ke rute yang tidak ada. Atur menggunakan .unknownRoute():

appRouter() => nyRoutes((router) {
  router.add(HomePage.path).initialRoute();

  router.add(NotFoundPage.path).unknownRoute();
});

Menggabungkan Semuanya

Berikut pengaturan router lengkap dengan semua jenis rute:

appRouter() => nyRoutes((router) {
  // First page for unauthenticated users
  router.add(LoginPage.path).initialRoute();

  // First page for authenticated users
  router.add(HomePage.path).authenticatedRoute();

  // 404 page
  router.add(NotFoundPage.path).unknownRoute();

  // Regular routes
  router.add(ProfilePage.path);
  router.add(SettingsPage.path);
});
Method Rute Tujuan
.initialRoute() Halaman pertama yang ditampilkan untuk pengguna yang tidak terautentikasi
.authenticatedRoute() Halaman pertama yang ditampilkan untuk pengguna yang terautentikasi
.previewRoute() Menggantikan keduanya selama pengembangan
.unknownRoute() Ditampilkan saat rute tidak ditemukan

Fungsi Helper

Nylo Website v7 menyediakan fungsi helper yang mencerminkan method kelas Auth:

Fungsi Helper Setara Dengan
authAuthenticate(data: user) Auth.authenticate(data: user)
authData() Auth.data()
authData(field: 'token') Auth.data(field: 'token')
authSet((data) => {...}) Auth.set((data) => {...})
authIsAuthenticated() Auth.isAuthenticated()
authLogout() Auth.logout()
authLogoutAll(sessions: [...]) Auth.logoutAll(sessions: [...])
authSyncToBackpack() Auth.syncToBackpack()
authKey() Kunci storage untuk sesi default
authDeviceId() Auth.deviceId()

Semua helper menerima parameter yang sama dengan pasangan kelas Auth-nya, termasuk parameter opsional session:

// Authenticate with a named session
await authAuthenticate(data: device, session: 'device');

// Read from a named session
dynamic deviceData = authData(session: 'device');

// Check a named session
bool deviceAuth = await authIsAuthenticated(session: 'device');