OAuth2授权码重定向流程在App内Web视图的工作原理及Flutter应用Google登录的redirect_uri配置方案咨询
先给你拆解下这个流程的核心步骤:
- 你的Flutter App启动内置WebView,加载Google的授权页面,同时带上OAuth必填参数:
client_id、response_type=code、redirect_uri、所需权限scope等。 - 用户在WebView内完成Google账号登录,确认授权你的App访问指定权限。
- Google授权服务器验证通过后,生成授权码并跳转到你指定的
redirect_uri地址。 - App内的WebView拦截这个重定向请求,从URL的查询参数里提取授权码,再把这个码发送给后端服务,由后端和Google服务器交换access_token、refresh_token等凭证。
针对移动端无法直接复用SPA redirect_uri的问题,有几种成熟的解决方案,我给你详细说明:
方案1:自定义URL Scheme(最常用、易实现)
自定义URL Scheme是移动端的经典方案,你可以给App注册一个独有的“协议”(比如myflutterapp://),当WebView跳转到这个协议的地址时,系统会唤起你的App,同时我们可以拦截请求拿到授权码。
具体操作:
给App注册Scheme
- Android端:打开
android/app/src/main/AndroidManifest.xml,在主Activity标签内添加以下intent-filter:<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <!-- 自定义Scheme,可根据你的App名称修改 --> <data android:scheme="myflutterapp" /> </intent-filter> - iOS端:打开
ios/Runner/Info.plist,添加如下配置:<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <!-- 自定义Scheme --> <string>myflutterapp</string> </array> </dict> </array>
- Android端:打开
配置Google OAuth的redirect_uri
前往Google Cloud控制台的OAuth 2.0客户端设置页面,把redirect_uri设置为:myflutterapp://oauth2callback(后面的oauth2callback是自定义路径,只要前后一致即可)。在Flutter里拦截重定向并提取授权码
使用webview_flutter插件时,通过navigationDelegate拦截URL请求:WebView( initialUrl: 'https://accounts.google.com/o/oauth2/v2/auth?client_id=你的客户端ID&response_type=code&redirect_uri=myflutterapp://oauth2callback&scope=openid%20email%20profile', navigationDelegate: (NavigationRequest request) { // 检测到自定义Scheme链接就拦截 if (request.url.startsWith('myflutterapp://oauth2callback')) { final uri = Uri.parse(request.url); final authCode = uri.queryParameters['code']; if (authCode != null) { // 拿到授权码后发送给后端 _sendAuthCodeToBackend(authCode); } // 阻止WebView加载该链接,留在App内 return NavigationDecision.prevent; } return NavigationDecision.navigate; }, )
方案2:App Links(Android)/Universal Links(iOS)(更安全)
如果追求更高安全性,避免其他App冒充你的Scheme,可以使用标准HTTPS域名作为redirect_uri,比如https://yourapp.com/oauth2callback。这种方式需要配置域名关联,让系统识别该域名的链接属于你的App,直接唤起App而非打开浏览器。
redirect_uri示例:
https://yourapp.com/oauth2callback
不过这个方案需要你拥有自己的域名,还要完成Android端的assetlinks.json配置和iOS端的apple-app-site-association配置,步骤相对繁琐,但安全性更强。
方案3:使用官方Google Sign-In插件(最省心)
其实Google官方为Flutter提供了google_sign_in插件,已经封装了整个OAuth流程,不用自己折腾WebView和重定向,直接就能拿到授权码:
final GoogleSignIn _googleSignIn = GoogleSignIn( scopes: ['email', 'profile'], // 若需给后端传授权码,这里填写Google Cloud中的Web客户端ID clientId: '你的Web客户端ID', ); Future<void> _signInWithGoogle() async { try { final GoogleSignInAccount? account = await _googleSignIn.signIn(); if (account != null) { final GoogleSignInAuthentication auth = await account.authentication; final String? authCode = auth.serverAuthCode; // 这就是我们需要的授权码 if (authCode != null) { _sendAuthCodeToBackend(authCode); } } } catch (e) { print('登录出错:$e'); } }
这个插件内部已处理所有重定向和授权逻辑,稳定性更高,我个人优先推荐这个方案。
内容的提问来源于stack exchange,提问作者şuayip üzelmez

