You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter中使用oauth2包实现Microsoft登录后无法重定向回应用

Flutter中使用oauth2包实现Microsoft登录后无法重定向回应用

看起来你遇到的是OAuth2登录完成后无法回调回Flutter应用的典型问题,这通常和URL Scheme平台配置缺失以及未处理授权回调逻辑有关,我来一步步帮你解决:


1. 先搞定最关键的:平台URL Scheme配置

系统需要知道哪个App应该响应微软的回调URL,所以必须给Android和iOS分别配置对应的URL Scheme,和你的azureRedirectUrl完全对应。

Android端配置

打开android/app/src/main/AndroidManifest.xml,找到主Activity(通常是io.flutter.embedding.android.FlutterActivity),在其内部添加如下intent-filter

<activity
    android:name=".MainActivity"
    android:exported="true"
    android:launchMode="singleTop"> <!-- 建议加上singleTop避免重复启动 -->
    <!-- 原有配置保持不变 -->
    
    <!-- 新增:捕获微软登录回调的URL -->
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        
        <!-- 完全匹配你的azureRedirectUrl:msauth://com.example.oauth_test/ru4om2-------------- -->
        <data
            android:scheme="msauth"
            android:host="com.example.oauth_test"
            android:path="/ru4om2--------------" />
    </intent-filter>
</activity>

iOS端配置

打开ios/Runner/Info.plist,添加以下配置(直接插在<dict>根节点内即可):

<!-- 允许App调用msauth协议 -->
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>msauth</string>
</array>

<!-- 配置App能响应的URL Scheme -->
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>msauth.com.example.oauth_test</string> <!-- 格式:msauth.你的Bundle ID -->
        </array>
        <key>CFBundleURLName</key>
        <string>com.example.oauth_test</string> <!-- 你的Bundle ID -->
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
    </dict>
</array>

⚠️ 额外提醒:必须在Azure Portal的App Registration后台,Authentication页面添加Mobile and desktop applications平台,并把你的azureRedirectUrl(比如msauth://com.example.oauth_test/ru4om2--------------)加入允许的重定向URI列表,否则微软会拒绝回调这个地址!


2. 完善登录回调逻辑(核心步骤)

你现在的代码只打开了浏览器,但没有监听App被唤起时的回调URL,没法把微软返回的授权码传给oauth2包完成Token获取。我们用uni_links包来监听回调:

第一步:添加依赖

pubspec.yaml里加入:

dependencies:
  flutter:
    sdk: flutter
  oauth2: ^2.0.2
  url_launcher: ^6.1.12
  uni_links: ^0.5.1 # 新增:用于监听App唤起的URL

执行flutter pub get安装依赖。

第二步:修改你的登录代码

更新State类的逻辑,加入URL监听和回调处理:

import 'package:uni_links/uni_links.dart';
import 'package:oauth2/oauth2.dart' as oauth2;
import 'package:url_launcher/url_launcher.dart';

// 你的State类部分
class _YourLoginPageState extends State<YourLoginPage> {
  String _status = 'Ready to Login';
  oauth2.AuthorizationCodeGrant? _grant;
  StreamSubscription? _uriSubscription;

  // 常量直接引用你定义的
  static const String clientId = azureClientId;
  static const String redirectUrl = azureRedirectUrl;
  static const String authorizationEndpoint = azureAuthorizationEndpoint;
  static const String tokenEndpoint = azureTokenEndpoint;
  static const List<String> scopes = azureOutlookScopes;

  @override
  void initState() {
    super.initState();
    // 初始化URL监听:处理冷启动/热启动的回调
    _initUriListener();
  }

  @override
  void dispose() {
    _uriSubscription?.cancel();
    _grant?.close();
    super.dispose();
  }

  // 初始化URL监听
  Future<void> _initUriListener() async {
    // 处理App未启动时被唤起的情况(冷启动)
    final initialUri = await getInitialUri();
    if (initialUri != null) {
      _handleAuthCallback(initialUri);
    }

    // 处理App在后台时被唤起的情况(热启动)
    _uriSubscription = uriLinkStream.listen(
      _handleAuthCallback,
      onError: (err) => debugPrint('URL监听错误: $err'),
    );
  }

  // 处理登录回调的URL,完成Token获取
  Future<void> _handleAuthCallback(Uri uri) async {
    if (_grant == null) {
      setState(() => _status = '错误:没有活跃的登录会话');
      return;
    }

    setState(() => _status = '处理登录响应中...');
    try {
      // 用回调URL完成授权,获取Token
      final client = await _grant!.handleAuthorizationResponse(uri.queryParameters);
      debugPrint('登录成功!Token: ${client.credentials.accessToken}');

      // 这里可以把Token保存到本地(比如shared_preferences)
      // 登录成功后的逻辑:比如跳转到首页
      setState(() => _status = '登录成功!');
    } catch (e) {
      setState(() => _status = '登录失败: $e');
      debugPrint('授权错误: $e');
    }
  }

  // 你的原有登录方法,做小调整
  Future<void> _startLogin() async {
    try {
      setState(() => _status = '打开浏览器中...');

      // 创建授权实例
      _grant = oauth2.AuthorizationCodeGrant(
        clientId,
        Uri.parse(authorizationEndpoint), // 必须转成Uri类型
        Uri.parse(tokenEndpoint),
      );

      // 生成微软登录URL
      final authUrl = _grant!.getAuthorizationUrl(
        Uri.parse(redirectUrl),
        scopes: scopes,
      );

      // 打开系统默认浏览器
      final launched = await launchUrl(
        authUrl,
        mode: LaunchMode.externalApplication, // 用外部浏览器打开,确保回调正常
      );

      if (!launched) {
        setState(() => _status = '错误:无法打开浏览器');
        return;
      }

      setState(() => _status = '浏览器已打开,请完成登录...');
    } catch (e) {
      setState(() => _status = '启动登录失败: $e');
      debugPrint('登录启动错误: $e');
    }
  }

  // 你的build方法保持不变...
}

3. 最后检查细节

  1. 确保azureRedirectUrl和平台配置、Azure后台的重定向URI完全一致,大小写、特殊字符都不能错
  2. 测试时尽量用真机,部分模拟器的浏览器可能存在回调问题
  3. 登录后如果还是有问题,查看debugPrint的日志,重点看是否有回调URL被捕获、是否有Azure返回的错误信息

按照上面的步骤配置和修改后,应该就能正常完成登录并回调回App了,有问题可以再查日志找具体原因~ 😊

火山引擎 最新活动