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

Flutter前端对接Azure App Services:如何通过Easy Auth实现Azure AD B2C认证?

绝对有可行方案!我之前帮好几个Flutter+Azure项目搞定过类似的认证需求,虽然没有官方适配Easy Auth的Flutter SDK,但咱们可以利用标准协议和Flutter生态里的工具来实现,下面是几个经过验证的方案:

方案1:用Flutter OAuth2/OIDC包直接对接Azure AD B2C(推荐)

Azure App Services的Easy Auth本质是基于标准的OAuth2/OpenID Connect协议,所以我们可以跳过前端直接调用Easy Auth的步骤,让Flutter直接和Azure AD B2C交互获取token,再带着token调用后端API——Easy Auth会自动验证这个token的有效性,完全不用后端写额外的认证代码。

推荐使用flutter_appauth包,它支持移动端安全的授权码+PKCE流程,完美适配Azure AD B2C:

步骤示例

  1. 在Azure AD B2C中创建一个「原生」类型的应用注册,设置重定向URI为com.your.app.package://callback(替换成你的Flutter包名)。
  2. 在Flutter项目中添加依赖:
    dependencies:
      flutter_appauth: ^6.1.1
      flutter_secure_storage: ^9.0.0
      http: ^1.1.0
    
  3. 编写认证和API调用代码:
    import 'package:flutter_appauth/flutter_appauth.dart';
    import 'package:flutter_secure_storage/flutter_secure_storage.dart';
    import 'package:http/http.dart' as http;
    
    final FlutterAppAuth _appAuth = FlutterAppAuth();
    final FlutterSecureStorage _secureStorage = FlutterSecureStorage();
    
    // Azure AD B2C配置参数
    const String _tenantId = "your-tenant-id";
    const String _policyName = "B2C_1_signupsignin"; // 你的用户流名称
    const String _clientId = "your-native-app-client-id";
    const String _redirectUri = "com.your.app.package://callback";
    const List<String> _scopes = [
      "openid",
      "offline_access",
      "https://$_tenantId.onmicrosoft.com/your-api/api.read" // 对应后端API的scope
    ];
    final String _authority = "https://$_tenantId.b2clogin.com/$_tenantId.onmicrosoft.com/$_policyName";
    
    // 发起登录请求
    Future<void> signIn() async {
      try {
        final result = await _appAuth.authorizeAndExchangeCode(
          AuthorizationTokenRequest(
            _clientId,
            _redirectUri,
            authority: _authority,
            scopes: _scopes,
            pkceEnabled: true, // 强制开启PKCE,移动端安全必备
          ),
        );
    
        if (result != null) {
          // 将token存入安全存储,避免明文泄露
          await _secureStorage.write(key: "access_token", value: result.accessToken);
          await _secureStorage.write(key: "refresh_token", value: result.refreshToken);
        }
      } catch (e) {
        print("登录失败: $e");
      }
    }
    
    // 调用受保护的Azure App Services API
    Future<void> callProtectedApi() async {
      final accessToken = await _secureStorage.read(key: "access_token");
      if (accessToken == null) return;
    
      final response = await http.get(
        Uri.parse("https://your-app-service.azurewebsites.net/api/your-endpoint"),
        headers: {"Authorization": "Bearer $accessToken"},
      );
    
      if (response.statusCode == 200) {
        // 处理成功响应
        print("API响应: ${response.body}");
      } else if (response.statusCode == 401) {
        // token过期,尝试刷新token
        await refreshToken();
        // 刷新成功后重新调用API
        await callProtectedApi();
      }
    }
    
    // 刷新token逻辑
    Future<void> refreshToken() async {
      final refreshToken = await _secureStorage.read(key: "refresh_token");
      if (refreshToken == null) return;
    
      try {
        final result = await _appAuth.token(
          TokenRequest(
            _clientId,
            _redirectUri,
            refreshToken: refreshToken,
            authority: _authority,
            scopes: _scopes,
          ),
        );
    
        if (result != null) {
          await _secureStorage.write(key: "access_token", value: result.accessToken);
          if (result.refreshToken != null) {
            await _secureStorage.write(key: "refresh_token", value: result.refreshToken);
          }
        }
      } catch (e) {
        print("刷新token失败,需要重新登录: $e");
        await signIn();
      }
    }
    
方案2:用WebView复用Easy Auth登录页面

如果你需要完全复用Azure App Services Easy Auth的自定义登录UI(比如已经配置了品牌化登录页),可以用webview_flutter包模拟浏览器登录流程:

步骤示例

  1. 在Azure App Services的Easy Auth配置中,添加你的Flutter应用自定义回调URL(比如com.your.app://auth-complete)到「允许的外部重定向URL」列表。
  2. 编写WebView登录页面:
    import 'package:webview_flutter/webview_flutter.dart';
    import 'package:flutter_secure_storage/flutter_secure_storage.dart';
    
    final FlutterSecureStorage _secureStorage = FlutterSecureStorage();
    
    class AuthWebView extends StatefulWidget {
      const AuthWebView({super.key});
    
      @override
      State<AuthWebView> createState() => _AuthWebViewState();
    }
    
    class _AuthWebViewState extends State<AuthWebView> {
      late WebViewController _webViewController;
    
      @override
      Widget build(BuildContext context) {
        return WebView(
          initialUrl: "https://your-app-service.azurewebsites.net/.auth/login/aadb2c",
          javascriptMode: JavascriptMode.unrestricted,
          navigationDelegate: (NavigationRequest request) {
            // 检测是否跳转到自定义回调URL
            if (request.url.startsWith("com.your.app://auth-complete")) {
              final uri = Uri.parse(request.url);
              final idToken = uri.queryParameters["id_token"];
              final accessToken = uri.queryParameters["access_token"];
    
              if (idToken != null && accessToken != null) {
                // 保存token到安全存储
                _secureStorage.write(key: "id_token", value: idToken);
                _secureStorage.write(key: "access_token", value: accessToken);
                // 关闭WebView返回主页面
                Navigator.pop(context);
              }
              return NavigationDecision.prevent;
            }
            return NavigationDecision.navigate;
          },
          onWebViewCreated: (controller) => _webViewController = controller,
        );
      }
    }
    
关键注意事项
  • 安全优先:移动端必须使用PKCE流程(方案1默认支持),绝对不要用隐式授权流程,避免token泄露。
  • token存储:一定要用flutter_secure_storage这类系统级安全存储工具,不要把token存在SharedPreferences或明文文件里。
  • 配置一致性:确保Azure AD B2C应用注册、Easy Auth配置中的租户ID、客户端ID、scope完全匹配,否则会出现认证失败。
  • 异常处理:记得处理token过期、网络异常等场景,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:57:36