Use the jwt_decoder
package to extract the user's role from the token.
import 'package:jwt_decoder/jwt_decoder.dart';
String getUserRole(String token) {
Map<String, dynamic> decodedToken = JwtDecoder.decode(token);
return decodedToken['role'] ?? 'guest'; // Ensure a default role
}
Define a middleware function that restricts access based on the user's role.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stockhive_mobile/screen/auth/login_page.dart';
import 'package:stockhive_mobile/screen/admin/departements/Departmentad.dart';
import 'package:stockhive_mobile/screen/collaborator/collaborator_dashboard.dart';
import 'package:stockhive_mobile/screen/user/user_dashboard.dart';
import 'package:jwt_decoder/jwt_decoder.dart';
class RoleBasedRoute extends StatelessWidget {
final Widget adminScreen;
final Widget collaboratorScreen;
final Widget userScreen;
final Widget defaultScreen;
RoleBasedRoute({
required this.adminScreen,
required this.collaboratorScreen,
required this.userScreen,
required this.defaultScreen,
});
Future<String> _getUserRole() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('jwtToken');
if (token == null || JwtDecoder.isExpired(token)) {
return 'guest';
}
Map<String, dynamic> decodedToken = JwtDecoder.decode(token);
return decodedToken['role'] ?? 'guest';
}
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: _getUserRole(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Scaffold(body: Center(child: CircularProgressIndicator()));
}
String role = snapshot.data!;
if (role == 'admin') {
return adminScreen;
} else if (role == 'collaborator') {
return collaboratorScreen;
} else if (role == 'user') {
return userScreen;
} else {
return defaultScreen;
}
},
);
}
}
3. Modify generateRoute
in AppRouter
Now, update the router to check for roles before navigating.
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case '/admin-dashboard':
return MaterialPageRoute(
builder: (_) => RoleBasedRoute(
adminScreen: DepartmentManagementPage(),
collaboratorScreen: LoginPage(),
userScreen: LoginPage(),
defaultScreen: LoginPage(),
),
);
case '/collaborator-dashboard':
return MaterialPageRoute(
builder: (_) => RoleBasedRoute(
adminScreen: LoginPage(),
collaboratorScreen: CollaboratorDashboard(),
userScreen: LoginPage(),
defaultScreen: LoginPage(),
),
);
case '/user-dashboard':
return MaterialPageRoute(
builder: (_) => RoleBasedRoute(
adminScreen: LoginPage(),
collaboratorScreen: LoginPage(),
userScreen: UserDashboard(),
defaultScreen: LoginPage(),
),
);
default:
return _errorRoute();
}
}
Modify your authentication flow to store the token in SharedPreferences
.
import 'package:shared_preferences/shared_preferences.dart';
Future<void> saveToken(String token) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('jwtToken', token);
}
SplashScreen
Modify SplashScreen
to check the role and redirect accordingly.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:jwt_decoder/jwt_decoder.dart';
class SplashScreen extends StatefulWidget {
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
super.initState();
_navigateToDashboard();
}
Future<void> _navigateToDashboard() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('jwtToken');
if (token == null || JwtDecoder.isExpired(token)) {
Navigator.pushReplacementNamed(context, '/login');
return;
}
Map<String, dynamic> decodedToken = JwtDecoder.decode(token);
String role = decodedToken['role'] ?? 'guest';
if (role == 'admin') {
Navigator.pushReplacementNamed(context, '/admin-dashboard');
} else if (role == 'collaborator') {
Navigator.pushReplacementNamed(context, '/collaborator-dashboard');
} else if (role == 'user') {
Navigator.pushReplacementNamed(context, '/user-dashboard');
} else {
Navigator.pushReplacementNamed(context, '/login');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
}
With this setup:
Users are redirected to the correct dashboard based on their role.
Routes are protected, ensuring unauthorized users can't access restricted pages.
JWT tokens are validated, and expired tokens redirect to login.
This method ensures secure role-based authentication in Flutter using JWT tokens.