You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:10:43