Flutter go_router:登录重定向后恢复导航的实现方法
实现go_router登录拦截后恢复原导航流程
要实现登录拦截后自动回到目标页面,核心是保存用户原本要访问的路径,登录成功后再跳转到该路径,下面提供几种可行方案:
方案1:通过URL查询参数传递目标路径
这种方式最简单直观,无需额外状态管理:
1. 重定向时保存目标路径
在GoRouter的redirect回调里,判断未登录时,把当前路径作为查询参数拼到登录页路由后:
final router = GoRouter( routes: [ GoRoute(path: '/', builder: (context, state) => const HomePage()), GoRoute(path: '/login', builder: (context, state) => const LoginPage()), GoRoute(path: '/authenticated/page', builder: (context, state) => const AuthenticatedPage()), ], redirect: (context, state) { // 替换成你的实际登录状态判断逻辑 final isLoggedIn = AuthService.instance.isLoggedIn; final isLoginPage = state.location.startsWith('/login'); if (!isLoggedIn && !isLoginPage) { // 将目标路径作为redirectTo参数传递给登录页,编码避免URL冲突 return '/login?redirectTo=${Uri.encodeComponent(state.location)}'; } // 已登录且在登录页时,跳转到保存的目标路径(默认首页) if (isLoggedIn && isLoginPage) { final redirectTo = Uri.decodeComponent(state.uri.queryParameters['redirectTo'] ?? '/'); return redirectTo; } // 无需重定向 return null; }, );
2. 登录成功后跳转回目标路径
在登录页的登录操作完成后,提取查询参数里的目标路径并跳转:
class LoginPage extends StatelessWidget { const LoginPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: ElevatedButton( onPressed: () async { // 执行登录逻辑 await AuthService.instance.login(); // 获取目标路径 final uri = GoRouterState.of(context).uri; final redirectTo = Uri.decodeComponent(uri.queryParameters['redirectTo'] ?? '/'); // 跳转回目标页面 context.go(redirectTo); }, child: const Text('登录'), ), ), ); } }
方案2:通过GoRouter的extra参数传递目标路径
如果不想把目标路径暴露在URL里,可以用GoRouter的extra参数传递:
1. 重定向时传递目标路径
redirect: (context, state) { final isLoggedIn = AuthService.instance.isLoggedIn; final isLoginPage = state.location.startsWith('/login'); if (!isLoggedIn && !isLoginPage) { // 将目标路径通过extra传递给登录页 return GoRouteMatch( route: router.routeInformationParser.configuration.routes.firstWhere((r) => r.path == '/login'), location: '/login', extra: state.location, ); } if (isLoggedIn && isLoginPage) { final redirectTo = state.extra as String? ?? '/'; return redirectTo; } return null; },
2. 登录页获取并跳转
onPressed: () async { await AuthService.instance.login(); final redirectTo = GoRouterState.of(context).extra as String? ?? '/'; context.go(redirectTo); },
方案3:通过状态管理保存目标路径
如果你的项目已经在用状态管理(比如Riverpod、Provider),可以用全局状态保存目标路径,适合复杂场景:
1. 定义状态管理Provider
final redirectTargetProvider = StateProvider<String?>((ref) => null);
2. 重定向时更新状态
redirect: (context, state) { final isLoggedIn = AuthService.instance.isLoggedIn; final isLoginPage = state.location.startsWith('/login'); final redirectTargetNotifier = ProviderScope.containerOf(context).read(redirectTargetProvider.notifier); if (!isLoggedIn && !isLoginPage) { redirectTargetNotifier.state = state.location; return '/login'; } if (isLoggedIn && isLoginPage) { final target = redirectTargetNotifier.state ?? '/'; redirectTargetNotifier.state = null; // 清空状态,避免重复跳转 return target; } return null; },
3. 登录成功后跳转
onPressed: () async { await AuthService.instance.login(); final ref = ProviderScope.containerOf(context); final redirectTo = ref.read(redirectTargetProvider) ?? '/'; context.go(redirectTo); },
内容的提问来源于stack exchange,提问作者wiradikusuma
相关产品推荐
相关产品推荐

