iOS设备Flutter InAppWebView微软AD登录SSL错误求助
解决iOS Flutter InAppWebView中微软AD登录的SSL错误
问题场景
集成微软AD登录的网页支持域内企业邮箱及外部邮箱登录,已开启浏览器弹窗权限。同一URL在iOS系统浏览器(Safari/Chrome)中可正常登录,但在Flutter InAppWebView中出现SSL错误,错误信息如下:
错误日志
flutter: }, sslError: SslError{code: UNSPECIFIED, message: Indicates the evaluation succeeded and the certificate is implicitly trusted, but user intent was not explicitly specified.}}}
当前实现代码
import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; class CustomInAppBrowser extends StatefulWidget { final String url; const CustomInAppBrowser({super.key, required this.url}); @override State<CustomInAppBrowser> createState() => _CustomInAppBrowserState(); } class _CustomInAppBrowserState extends State<CustomInAppBrowser> { final GlobalKey webViewKey = GlobalKey(); String url = ''; String title = ''; double progress = 0; bool? isSecure; InAppWebViewController? webViewController; @override void initState() { super.initState(); url = widget.url; } @override Widget build(BuildContext context) { return Scaffold( body: Column( children: <Widget>[ Expanded( child: Stack( children: [ InAppWebView( key: webViewKey, initialUrlRequest: URLRequest(url: WebUri(widget.url)), onNavigationResponse: (controller, navigationResponse) async { debugPrint('navigationResponse: ${navigationResponse}'); return NavigationResponseAction.ALLOW; }, onPermissionRequest: (controller, permissionRequest) async { debugPrint('permissionRequest: ${permissionRequest}'); return PermissionResponse.fromMap({ 'resources': permissionRequest.resources, 'action': PermissionResponseAction.GRANT }); }, onReceivedServerTrustAuthRequest: (InAppWebViewController controller, URLAuthenticationChallenge challenge) async { debugPrint('onReceivedServerTrustAuthRequest: ${challenge}'); return ServerTrustAuthResponse(action: ServerTrustAuthResponseAction.PROCEED); }, initialSettings: InAppWebViewSettings( transparentBackground: true, safeBrowsingEnabled: true, isFraudulentWebsiteWarningEnabled: true, ), onWebViewCreated: (controller) async { webViewController = controller; if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { await controller.startSafeBrowsing(); } }, onLoadStart: (controller, url) { if (url != null) { setState(() { this.url = url.toString(); isSecure = urlIsSecure(url); }); } }, onLoadStop: (controller, url) async { if (url != null) { setState(() { this.url = url.toString(); }); } final sslCertificate = await controller.getCertificate(); setState(() { isSecure = sslCertificate != null || (url != null && urlIsSecure(url)); }); }, onUpdateVisitedHistory: (controller, url, isReload) { if (url != null) { setState(() { this.url = url.toString(); }); } }, onTitleChanged: (controller, title) { if (title != null) { setState(() { this.title = title; }); } }, onProgressChanged: (controller, progress) { setState(() { this.progress = progress / 100; }); }, ), progress < 1.0 ? LinearProgressIndicator(value: progress) : Container(), ], ), ), ], ), ); } void handleClick(int item) async { switch (item) { case 0: await InAppBrowser.openWithSystemBrowser(url: WebUri(url)); break; case 1: await webViewController?.clearCache(); if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { await webViewController?.clearHistory(); } setState(() {}); break; } } static bool urlIsSecure(Uri url) { return (url.scheme == "https") || isLocalizedContent(url); } static bool isLocalizedContent(Uri url) { return (url.scheme == "file" || url.scheme == "chrome" || url.scheme == "data" || url.scheme == "javascript" || url.scheme == "about"); } }
已配置的Info.plist内容
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key><true/> </dict>
解决方案
1. 让InAppWebView使用系统证书信任策略
修改InAppWebViewSettings,添加serverTrustAuthenticationPolicy配置,让WebView和系统浏览器使用相同的证书信任规则:
initialSettings: InAppWebViewSettings( transparentBackground: true, safeBrowsingEnabled: true, isFraudulentWebsiteWarningEnabled: true, // 启用系统级证书信任 serverTrustAuthenticationPolicy: ServerTrustAuthenticationPolicy.USE_DEVICE_SETTINGS, ),
该配置会让InAppWebView继承iOS系统的证书信任列表,若设备已信任企业CA证书(微软AD相关),WebView会自动信任对应域名的证书。
2. 优化ATS配置(替代全局允许)
全局开启NSAllowsArbitraryLoads存在安全风险,建议针对微软AD相关域名配置精确的ATS例外:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <false/> <key>NSExceptionDomains</key> <dict> <!-- 替换为你的AD登录主域名 --> <key>your-ad-login-domain.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSTemporaryExceptionMinimumTLSVersion</key> <string>TLSv1.2</string> </dict> <!-- 添加微软AD授权相关域名 --> <key>login.microsoftonline.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> </dict> </dict> </dict>
3. 完善证书验证回调逻辑
若上述方案无效,可在onReceivedServerTrustAuthRequest中添加针对性的证书验证逻辑,确保仅信任目标域名的合法证书:
onReceivedServerTrustAuthRequest: (controller, challenge) async { final trustedDomains = ["your-ad-login-domain.com", "login.microsoftonline.com"]; // 验证请求域名是否在信任列表中 if (trustedDomains.contains(challenge.protectionSpace.host)) { return ServerTrustAuthResponse(action: ServerTrustAuthResponseAction.PROCEED); } // 非信任域名默认拒绝 return ServerTrustAuthResponse(action: ServerTrustAuthResponseAction.CANCEL); },
内容的提问来源于stack exchange,提问作者Secret Santa
相关产品推荐
相关产品推荐

