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

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端同样会调用浏览器处理导航:

  1. 先添加依赖到pubspec.yaml:
dependencies:
  url_launcher: ^6.2.5
  1. 修改登录代码:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:52:53