Skip to content

Commit d5fc640

Browse files
authored
Merge pull request #122 from flutter-news-app-full-source-code/fix/rbac
refactor(router): enhance role-based access control
2 parents b345cf8 + 1b709b2 commit d5fc640

File tree

1 file changed

+36
-10
lines changed

1 file changed

+36
-10
lines changed

lib/router/router.dart

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,24 +86,50 @@ GoRouter createRouter({
8686

8787
// --- Role-Based Access Control (RBAC) ---
8888
final userRole = context.read<AppBloc>().state.user?.dashboardRole;
89-
final destinationRouteName = state.topRoute?.name;
9089

91-
// Allow navigation if role is not yet determined or route is unknown.
92-
if (userRole == null || destinationRouteName == null) {
90+
// Allow navigation if the user role isn't determined yet.
91+
if (userRole == null) {
9392
return null;
9493
}
9594

96-
final allowedRoutes = routePermissions[userRole];
95+
// A local map to resolve top-level route names to their base paths.
96+
// This is the single source for this mapping within the redirect logic.
97+
const topLevelPaths = {
98+
Routes.overviewName: Routes.overview,
99+
Routes.contentManagementName: Routes.contentManagement,
100+
Routes.userManagementName: Routes.userManagement,
101+
Routes.appConfigurationName: Routes.appConfiguration,
102+
};
97103

98-
// Check if the user is trying to access a route they are not
99-
// permitted to view.
104+
// Get the set of authorized route *names* for the user's role from
105+
// the single source of truth: route_permissions.dart.
106+
final allowedRouteNames = routePermissions[userRole] ?? {};
107+
108+
// Convert the allowed route names into a list of their base paths.
109+
final authorizedPaths = allowedRouteNames
110+
.map((name) {
111+
final path = topLevelPaths[name];
112+
assert(
113+
path != null,
114+
'Configuration error: Route name "$name" from routePermissions is not defined in topLevelPaths.',
115+
);
116+
return path;
117+
})
118+
.whereType<String>()
119+
.toList();
120+
121+
// Check if the destination path starts with any of the authorized base
122+
// paths, or if it's the universally accessible settings page.
100123
final isAuthorized =
101-
allowedRoutes?.contains(destinationRouteName) ?? false;
124+
authorizedPaths.any(
125+
currentLocation.startsWith,
126+
) ||
127+
currentLocation.startsWith(Routes.settings);
102128

103-
// Universally allowed routes like 'settings' are exempt from this check.
104-
if (!isAuthorized && destinationRouteName != Routes.settingsName) {
129+
if (!isAuthorized) {
105130
print(
106-
' Action: Unauthorized access to "$destinationRouteName". '
131+
' Action: Unauthorized access to "$currentLocation" for role '
132+
'$userRole. Authorized base paths: $authorizedPaths. '
107133
'Redirecting to $overviewPath.',
108134
);
109135
// Redirect unauthorized users to the overview page. This is a safe

0 commit comments

Comments
 (0)