Flutter中Azure AD认证下动态路由的处理方案咨询
解决方案
核心思路:捕获用户初始访问的动态子路由并暂存,重定向到根路由完成Azure AD认证,认证成功后跳转回原子路由。具体实现步骤如下:
1. 捕获并暂存初始访问的子路由
应用启动时检测Web端当前路径,若不是根路由则暂存该路径,强制跳转到根路由触发认证流程:
void main() async { WidgetsFlutterBinding.ensureInitialized(); if (kIsWeb) { final currentUri = Uri.base; if (currentUri.path != '/') { // 用SharedPreferences暂存路由(也可使用内存变量,刷新后会丢失) final prefs = await SharedPreferences.getInstance(); await prefs.setString('pending_route', currentUri.path); // 强制跳转到根路由 window.location.href = '/'; } } runApp(const PlatformWidget()); }
2. 配置Azure AD重定向URI
在Azure AD应用注册中,仅配置根路由作为重定向URI(如https://example.com/),无需添加所有动态子路由。
3. 调整AuthState与AuthBloc逻辑
给AuthState添加pendingRoute字段传递暂存路由,认证成功后读取该路由并随状态发射:
修改AuthState
enum AuthStatus { inProgress, authenticated, failure } class AuthState extends Equatable { final AuthStatus status; final String? email; final String? error; final String? pendingRoute; const AuthState._({ required this.status, this.email, this.error, this.pendingRoute, }); const AuthState.inProgress() : this._(status: AuthStatus.inProgress); const AuthState.authenticated(String email, {String? pendingRoute}) : this._(status: AuthStatus.authenticated, email: email, pendingRoute: pendingRoute); const AuthState.failure(String error) : this._(status: AuthStatus.failure, error: error); @override List<Object?> get props => [status, email, error, pendingRoute]; }
更新AuthBloc认证逻辑
Future<void> _onAuthInitialization(AuthInitializationEvent event, Emitter<AuthState> emit) async { emit(const AuthState.inProgress()); try { final token = await _authRepository.getToken(); final email = await _authRepository.authenticate(token); String? pendingRoute; if (kIsWeb) { final prefs = await SharedPreferences.getInstance(); pendingRoute = prefs.getString('pending_route'); await prefs.remove('pending_route'); // 用完清除暂存 } emit(AuthState.authenticated(email, pendingRoute: pendingRoute)); } catch (e) { emit(AuthState.failure(e.toString())); } }
4. 调整AppView路由跳转逻辑
认证成功后检测暂存路由,若存在则用GoRouter跳转回该路由:
class _AppViewState extends State<AppView> { late final GoRouter _router; @override void initState() { super.initState(); _router = GoRouter( routes: [ GoRoute(path: '/', builder: (ctx, state) => const RootWidget()), GoRoute(path: '/some/dynamic/:id', builder: (ctx, state) => DynamicWidget(id: state.pathParameters['id']!)), // 其他路由配置... ], ); } @override Widget build(BuildContext context) { return BlocBuilder<AuthBloc, AuthState>(builder: (context, state) { switch (state.status) { case AuthStatus.inProgress: return const Center(child: CircularProgressIndicator()); case AuthStatus.authenticated: // 认证成功后跳转暂存路由 WidgetsBinding.instance.addPostFrameCallback((_) { if (state.pendingRoute != null) { _router.go(state.pendingRoute!); } }); return MaterialApp.router(routerConfig: _router); case AuthStatus.failure: return Center(child: Text('认证失败: ${state.error}')); } }); } }
5. 修正aad_oauth配置
明确指定根路由作为重定向URI,确保认证后回到根路由:
class AuthRepository { late AadOAuth oauth; AuthRepository() { final config = Config( tenant: "...", clientId: "...", scope: "User.Read", navigatorKey: globalNavigatorKey, webUseRedirect: true, redirectUri: "https://example.com/", // 根路由作为重定向URI loader: const Center(child: CircularProgressIndicator()), ); oauth = AadOAuth(config); } // 其他方法保持不变... }
内容的提问来源于stack exchange,提问作者Fabian M
相关产品推荐
相关产品推荐

