如何基于AutoRoute实现Flutter认证状态驱动的声明式导航
实现基于认证状态的AutoRoute声明式导航
核心思路
不需要大幅修改现有AuthCubit,主要通过AutoRoute路由守卫+监听认证状态动态切换初始路由实现需求。以下是分步实现方案:
1. 完善AppRouter路由配置
先确保AppRouter中正确声明目标路由,并且不设置固定初始路由(留给动态逻辑判断):
@MaterialAutoRouter( routes: [ AutoRoute(page: LoginPage, initial: false), AutoRoute(page: DashboardPage, initial: false), // 其他业务路由按需添加 ], ) class AppRouter extends _$AppRouter {}
2. 实现AuthGuard路由守卫
创建AutoRoute的路由守卫,拦截需要登录权限的页面,根据认证状态决定放行或重定向:
@injectable class AuthGuard extends AutoRouteGuard { final AuthCubit _authCubit; AuthGuard(this._authCubit); @override void onNavigation(NavigationResolver resolver, StackRouter router) { final authState = _authCubit.state; if (authState is _IsLoggedIn) { // 已登录,允许访问目标页面 resolver.next(true); } else { // 未登录,重定向到登录页 router.push(const LoginRoute()); resolver.next(false); } } }
然后给需要登录权限的路由绑定守卫(比如Dashboard):
@MaterialAutoRouter( routes: [ AutoRoute(page: LoginPage, initial: false), AutoRoute( page: DashboardPage, initial: false, guards: [AuthGuard], // 给Dashboard添加登录守卫 ), ], ) class AppRouter extends _$AppRouter {}
3. 监听认证状态,动态设置初始路由
在应用入口Widget(比如MyApp)中,通过BlocBuilder监听AuthCubit状态,动态决定启动时的初始路由:
class MyApp extends StatelessWidget { final AppRouter _appRouter; final AuthCubit _authCubit; const MyApp({ super.key, required AppRouter appRouter, required AuthCubit authCubit, }) : _appRouter = appRouter, _authCubit = authCubit; @override Widget build(BuildContext context) { return BlocBuilder<AuthCubit, AuthState>( bloc: _authCubit, builder: (context, state) { // 处理启动时的加载状态(可选,优化用户体验) if (state is _Loading) { return const Scaffold(body: Center(child: CircularProgressIndicator())); } return MaterialApp.router( routerDelegate: _appRouter.delegate( initialRoute: state is _IsLoggedIn ? DashboardRoute.name : LoginRoute.name, ), routeInformationParser: _appRouter.defaultRouteParser(), ); }, ); } }
4. 登录/登出后的路由跳转
在登录成功或登出的逻辑中,更新认证状态后手动切换路由:
// 登录成功示例 await _tokenRepository.saveAccessToken(newAccessToken); await _tokenRepository.saveRefreshToken(newRefreshToken); _authStateRepository.setUserLoggedIn(true); // 跳转到Dashboard,替换当前路由栈 context.router.replace(const DashboardRoute()); // 登出示例 await _tokenRepository.saveAccessToken(null); await _tokenRepository.saveRefreshToken(null); _authStateRepository.setUserLoggedIn(false); // 跳转到Login,替换当前路由栈 context.router.replace(const LoginRoute());
对现有代码的小优化建议
- 给AuthState添加加载状态:当前AuthCubit初始状态直接设为
isLoggedIn(),但启动时token检查还未完成,建议新增加载状态避免闪屏:
@freezed class AuthState with _$AuthState { const factory AuthState.loading() = _Loading; // 新增加载状态 const factory AuthState.isLoggedIn() = _IsLoggedIn; const factory AuthState.isLoggedOut() = _IsLoggedOut; }
然后修改AuthCubit构造函数:
AuthCubit(this._authStateRepository) : super(const AuthState.loading()) { _init(); }
- 合并TokenRepository的检查逻辑:当前
_checkForAccessToken和_checkForRefreshToken并行调用,会导致setUserLoggedIn被触发两次,建议只保留refresh token的检查(因为refresh token存在即可证明用户已登录,access token过期可自动刷新):
void _init() { _checkForRefreshToken(); // 只检查refresh token }
内容的提问来源于stack exchange,提问作者Dominik
相关产品推荐
相关产品推荐

