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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 03:04:57