go_router_auth 0.1.0
go_router_auth: ^0.1.0 copied to clipboard
A simple auth guard for GoRouter. Handles login redirect, public routes, loading state, and protected UI widgets. Framework-agnostic.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:go_router_auth/go_router_auth.dart';
/// Simple in-memory auth service for demonstration.
class AuthService extends ChangeNotifier {
bool _isLoggedIn = false;
bool get isLoggedIn => _isLoggedIn;
Future<void> login(String email, String password) async {
await Future.delayed(const Duration(seconds: 1));
_isLoggedIn = true;
notifyListeners();
}
Future<void> logout() async {
_isLoggedIn = false;
notifyListeners();
}
}
void main() {
final authService = AuthService();
final authGuard = AuthGuard(
isLoggedIn: () => authService.isLoggedIn,
loginPath: '/login',
homePath: '/dashboard',
publicRoutes: ['/login'],
);
final router = GoRouter(
initialLocation: '/dashboard',
redirect: authGuard.redirect,
refreshListenable: authGuard,
routes: [
GoRoute(
path: '/login',
builder: (context, state) => LoginPage(
authService: authService,
authGuard: authGuard,
),
),
GoRoute(
path: '/dashboard',
builder: (context, state) => DashboardPage(
authService: authService,
authGuard: authGuard,
),
),
GoRoute(
path: '/profile',
builder: (context, state) => ProfilePage(
authService: authService,
authGuard: authGuard,
),
),
],
);
runApp(MyApp(router: router));
}
class MyApp extends StatelessWidget {
final GoRouter router;
const MyApp({super.key, required this.router});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Auth Guard Demo',
theme: ThemeData(primarySwatch: Colors.indigo),
routerConfig: router,
);
}
}
// ─── Pages ──────────────────────────────────────────────────────
class LoginPage extends StatelessWidget {
final AuthService authService;
final AuthGuard authGuard;
const LoginPage({
super.key,
required this.authService,
required this.authGuard,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Selamat datang',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text('Silakan login untuk melanjutkan'),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () async {
await authService.login('test@test.com', '123456');
authGuard.notify(); // GoRouter redirects to /dashboard
},
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
),
child: const Text('Login Demo'),
),
],
),
),
),
);
}
}
class DashboardPage extends StatelessWidget {
final AuthService authService;
final AuthGuard authGuard;
const DashboardPage({
super.key,
required this.authService,
required this.authGuard,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Dashboard'),
actions: [
IconButton(
icon: const Icon(Icons.logout),
onPressed: () async {
await authService.logout();
authGuard.notify(); // GoRouter redirects to /login
},
),
],
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.check_circle, size: 64, color: Colors.green),
const SizedBox(height: 16),
const Text(
'Login berhasil!',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text('Ini halaman yang dilindungi'),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => context.push('/profile'),
child: const Text('Ke Profile'),
),
],
),
),
);
}
}
class ProfilePage extends StatelessWidget {
final AuthService authService;
final AuthGuard authGuard;
const ProfilePage({
super.key,
required this.authService,
required this.authGuard,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Profile')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// ProtectedRoute — user info hanya muncul jika login
ProtectedRoute(
authGuard: authGuard,
child: Column(
children: [
const CircleAvatar(
radius: 40,
child: Icon(Icons.person, size: 40),
),
const SizedBox(height: 16),
const Text(
'User Profile',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const Text('user@example.com'),
],
),
unauthenticatedBuilder: (context) => const Text(
'Silakan login untuk melihat profile',
style: TextStyle(color: Colors.grey),
),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => context.pop(),
child: const Text('Kembali'),
),
],
),
),
);
}
}