Flutter Web登录重定向:如何展示Google登录回调页面?
问题描述
在Flutter Web中调用以下登录接口代码时,未触发Google OAuth2的重定向登录页面,但将相同URL复制到浏览器地址栏却能正常跳转至Google登录页面。如何让Flutter Web应用向用户展示该登录页面?
Flutter Web登录代码:
Future<DataResponse> login({required String userId}) async { final headers = { 'Allow-Control-Allow-Origin': '*', 'Content-Type': 'application/json', 'Accept': '*/*', }; final uri = Uri.parse("${Env.BASE_URL}/login?userId=$userId"); print("url status: $uri"); final request = http.Request('GET', uri)..followRedirects = true..headers.addAll(headers); final response = await request.send(); return DataResponse(statusCode: response.statusCode, message: '', data: response.stream); }
后端Node.js + Passport Google OAuth2代码:
app.get("/login", (req, res, next) => { const options = { accessType: "offline", scope: [ "email", "profile", ], state: req.query.userId as string | undefined, }; passport.authenticate("google", options)(req, res, next); }); app.get("/login/callback", passport.authenticate("google", {}), async (req, res) => { { const user = req.user as (iUser | undefined); if (!user) { // Redirect to login page return res.status(401).send("Unauthorized"); } const databaseId = req.query.state as string | undefined; if (!databaseId) { return res.status(422).send("No user id was provided"); } // state comes from the youtube/login route user.databaseId = databaseId; user.service = "google"; try { await database.upsertUser(user); return res.status(204).send(); } catch (e) { console.log("Error: ", e); return res.status(500).send(e); } } });
问题原因
你当前使用http.Request发起的是后台HTTP请求(由Dart虚拟机处理),而非浏览器层面的导航请求。这类请求的重定向响应只会在Dart代码内部处理,不会触发浏览器的页面跳转,因此用户看不到Google登录页面。只有浏览器主动发起的导航(比如地址栏输入URL、点击链接)才会处理OAuth2的重定向并渲染登录页面。
解决方案
需要让浏览器直接发起登录URL的导航请求,而非在Dart代码中后台调用。以下是两种可行方案:
方案1:使用Dart的dart:js直接调用浏览器API
通过window.open让浏览器打开登录URL,触发OAuth2的跳转流程:
import 'dart:js' as js; Future<void> login({required String userId}) async { final loginUrl = Uri.parse("${Env.BASE_URL}/login?userId=$userId"); // 在新标签页打开登录页面,如需在当前页打开可将'_blank'改为'_current' js.context.callMethod('open', [loginUrl.toString(), '_blank']); }
方案2:使用url_launcher包(跨平台友好)
url_launcher是Flutter官方推荐的URL跳转包,Web端同样会调用浏览器处理导航:
- 先添加依赖到
pubspec.yaml:
dependencies: url_launcher: ^6.2.5
- 修改登录代码:
import 'package:url_launcher/url_launcher.dart'; Future<void> login({required String userId}) async { final loginUrl = Uri.parse("${Env.BASE_URL}/login?userId=$userId"); if (await canLaunchUrl(loginUrl)) { // 用外部浏览器(或当前浏览器标签)打开URL await launchUrl(loginUrl, mode: LaunchMode.externalApplication); } }
后续回调处理
登录完成后,后端的/login/callback需要调整逻辑,将用户重定向回Flutter Web应用的指定页面,而非返回204状态码。例如:
try { await database.upsertUser(user); // 重定向回Flutter应用的登录成功页面,可携带状态参数 return res.redirect(`https://your-flutter-app-domain.com/login-success?state=${databaseId}`); } catch (e) { console.log("Error: ", e); // 重定向回登录错误页面 return res.redirect(`https://your-flutter-app-domain.com/login-error?error=${encodeURIComponent(e.toString())}`); }
之后在Flutter Web中,通过监听路由变化获取URL参数,完成用户登录状态的同步(比如存储token、更新UI)。
内容的提问来源于stack exchange,提问作者Andrey Solera
相关产品推荐
相关产品推荐

