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

iOS平台下Flutter通过授权码交换获取OAuth2 Token时出现阻塞问题

解决Flutter AppAuth + Azure B2C在iOS上登录后阻塞的问题

看起来你碰到的是flutter_appauth和Azure B2C在iOS端集成时的典型兼容性问题——登录完成后浏览器关闭,但代码卡在authorizeAndExchangeCode那里一直没响应。结合你提到的已知问题,我整理了几个针对性的解决步骤,你可以逐一尝试:

1. 检查Azure B2C应用的重定向URI配置

Azure B2C对iOS移动应用的重定向URI有特定要求,自定义HTTP/HTTPS URI容易导致回调失败:

  • 登录Azure门户,找到你的B2C应用注册,把重定向URI改成msal<你的客户端ID>://auth格式(比如msal123456-7890-abcdef-ghijkl://auth)。
  • 同时在iOS项目的Info.plist中添加对应的URL Scheme,确保系统能把回调路由到你的App:
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>msal<你的客户端ID></string>
    </array>
  </dict>
</array>

2. 调整AuthorizationTokenRequest的参数设置

几个参数的调整能避免Azure B2C的静默认证或自动发现带来的异常:

  • 强制添加promptValues: ['login'],确保每次都触发完整的登录流程,跳过可能的静默认证回调问题:
final request = AuthorizationTokenRequest(
  B2C_CLIENT_ID, 
  B2C_REDIRECT_URI,
  discoveryUrl: 'https://$B2C_DOMAIN/.well-known/openid-configuration',
  scopes: ['openid', 'profile', 'offline_access'],
  promptValues: ['login'], // 新增这个参数
);
  • 尝试手动指定服务配置,替代自动发现。Azure B2C的端点需要带上策略名称,所以直接写死端点更可靠:
// 替换成你的B2C策略名称,比如B2C_1_signupsignin1
final policyName = 'YOUR_B2C_POLICY_NAME';
final serviceConfig = AuthorizationServiceConfiguration(
  authorizationEndpoint: 'https://$B2C_DOMAIN/oauth2/v2.0/authorize?p=$policyName',
  tokenEndpoint: 'https://$B2C_DOMAIN/oauth2/v2.0/token?p=$policyName',
);

final request = AuthorizationTokenRequest(
  B2C_CLIENT_ID, 
  B2C_REDIRECT_URI,
  serviceConfiguration: serviceConfig,
  scopes: ['openid', 'profile', 'offline_access'],
  promptValues: ['login'],
);

3. 确保iOS的AppDelegate正确处理URL回调

如果App没有正确接收Azure B2C的回调,插件就会一直等待响应。修改你的AppDelegate代码:

Swift版本:

import UIKit
import Flutter
import flutter_appauth

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    open url: URL,
    options: [UIApplication.OpenURLOptionsKey : Any] = [:]
  ) -> Bool {
    // 优先让AppAuth插件处理回调
    if flutter_appauth.AppAuthPlugin.sharedInstance.handle(url) {
      return true
    }
    return super.application(application, open: url, options: options)
  }
}

Objective-C版本:

#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
#import "GeneratedPluginRegistrant.h"
#import <flutter_appauth/FLTAppAuthPlugin.h>

@interface AppDelegate : FlutterAppDelegate
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
    if ([[FLTAppAuthPlugin sharedInstance] handleURL:url]) {
        return YES;
    }
    return [super application:application openURL:url options:options];
}

@end

4. 拆分授权与令牌交换的临时规避方案

如果上述方法都无效,可以绕过authorizeAndExchangeCode的内部逻辑,手动拆分授权和令牌交换步骤:

// 第一步:发起授权请求,获取授权码
final authResponse = await appAuth.authorize(
  AuthorizationRequest(
    B2C_CLIENT_ID,
    B2C_REDIRECT_URI,
    serviceConfiguration: serviceConfig, // 用前面定义的serviceConfig
    scopes: ['openid', 'profile', 'offline_access'],
    promptValues: ['login'],
  ),
);

// 第二步:用授权码手动交换令牌
if (authResponse.authorizationCode != null) {
  final tokenResponse = await appAuth.token(TokenRequest(
    B2C_CLIENT_ID,
    B2C_REDIRECT_URI,
    authorizationCode: authResponse.authorizationCode,
    serviceConfiguration: serviceConfig,
    scopes: ['openid', 'profile', 'offline_access'],
  ));
  // 在这里处理tokenResponse,获取accessToken、idToken等
}

这种方式能避开authorizeAndExchangeCode内部的阻塞问题,很多开发者用这个方法解决了类似的Azure B2C集成问题。

内容的提问来源于stack exchange,提问作者Umair

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 08:53:13