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

Flutter集成Passport.js Google OAuth2.0登录遇空值异常求解决

问题:Flutter集成Passport.js Google OAuth2登录的调用错误

问题背景

已有可正常运行的登录功能,需转为Flutter应用中基于Passport.js和Google OAuth2.0的signInWithGoogle功能,但不清楚如何调用/google回调URL及处理响应,点击按钮时出现Unexpected null value错误。

现有代码

后端路由(routes.ts)

router.post('/login', AuthController.login);
router.get('/google', passport.authenticate('google', { scope: 'profile email' }));
router.get('/google/callback', AuthController.googleCallback);

后端回调处理(auth.ts)

googleCallback: async (req: Request, res: Response, next: NextFunction): Promise<any> => {
    passport.authenticate(
      'google',
      { failureRedirect: `${process.env.FRONTEND_URL}?auth=social&responseType=error`, session: false },
      async (err, user) => {
        req.login(user, { session: false }, async (error) => {
          if (error) return next(error);

          const body = { _id: user._id, email: user.email };
          const token = jwt.sign({ user: body }, process.env.SECRET);

          const payload = {
            auth: 'social',
            responseType: 'success',
            provider: SocialProvider.Google,
            token,
          };
          const queryString = new URLSearchParams(payload).toString();
          return res.cookie('token', token).redirect(`${process.env.FRONTEND_URL}/?${queryString}`);
        });
      }
    )(req, res, next);
  },

Flutter端API调用(SignInWithGoogleApi)

import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:ltp/utils/navigateFromResponse.dart';
import '../API/apiconstants.dart';

NavigateFromResponse navigateFromResponse = NavigateFromResponse();

ApiConstants apiConstants = ApiConstants();
Dio dio = Dio();

class SignInWithGoogleApi {

  Future siginwithgoogle() async {
    try {
      Response response = await dio.post(ApiConstants().baseURL + "google",
        options: Options(
            followRedirects: true,
            validateStatus: (status) {
              return status! <= 500;
            }
        ),
      );
      return response;
    }
    on DioError catch (dioError) {
      if (dioError.response!.statusCode == 401) {
        debugPrint(dioError.message);
      }
    }
  }
}

Flutter按钮点击逻辑

ElevatedButton(
  onPressed: () => {
    setState((){
      isLoading = true;
    }),
    googleApi.siginwithgoogle().then((value) async =>
    {
      if( value.statusCode == 200){
        profileInfoProvider.profileInfoProfileID(value.data["user"]["_id"]),
        profileInfoProvider.profileInfoToken(value.data["token"]),
        profileInfoProvider.profileInfoName(value.data["user"]["fullName"]),
        profileInfoProvider.profileInfoObject(value.data["user"]),
        profileInfoProvider.profileInitialAssign(value.data["user"]["fullName"]),
        profileInfoProvider.profileColorSet(randomNumber.nextInt(7)),
        channelApi.getAllChannels().then((value) async => {
                  channelProvider.channelListRefreshed(value.data),
                  setState((){
                    isLoading = false;
                  }),
                  Get.offAllNamed('/wrapper')
            }),
      }
      else{
        setState((){
          isLoading = false;
        }),
        ScaffoldMessenger.of(context)
            .showSnackBar(const SnackBar(
              behavior: SnackBarBehavior.floating,
              duration: Duration(seconds: 2),
              content: Text(
                'Invalid/Enter Credentials')))
        }
     }
  )
},

错误信息

[GETX] NEW ROUTE null
Error: Unexpected null value.
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49      throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 528:63  nullCheck
packages/ltp/API/sigininwithgoogle.dart 27:41                                     siginwithgoogle
...

错误原因分析

  1. 请求方法不匹配:后端/google路由是GET请求,但Flutter端误用POST调用,导致后端返回无效响应,触发null值错误。
  2. OAuth2流程理解偏差:Google OAuth2需要用户在浏览器中完成授权登录,直接用Dio发起后台请求无法触发用户交互,会得到无效的重定向响应,无法获取预期的用户数据和token。

解决方案

步骤1:引入浏览器授权跳转依赖

使用flutter_web_auth包实现浏览器授权跳转(支持移动端和Web),先在pubspec.yaml添加依赖:

dependencies:
  flutter_web_auth: ^0.5.0

步骤2:重构Flutter端API调用类

import 'package:flutter_web_auth/flutter_web_auth.dart';
import 'package:ltp/API/apiconstants.dart';
import 'package:flutter/cupertino.dart';

ApiConstants apiConstants = ApiConstants();

class SignInWithGoogleApi {
  Future<Map<String, String>?> siginwithgoogle() async {
    try {
      // 构造后端授权跳转URL
      final authorizationUrl = "${apiConstants.baseURL}google";
      // 回调URL需与Google Cloud控制台、后端FRONTEND_URL配置一致
      final callbackUrlScheme = "your-app-scheme"; // 示例:ltp://callback

      // 打开Google授权页面
      final result = await FlutterWebAuth.authenticate(
        url: authorizationUrl,
        callbackUrlScheme: callbackUrlScheme,
      );

      // 解析回调返回的查询参数
      final queryParams = Uri.parse(result).queryParameters;
      return queryParams;
    } catch (e) {
      debugPrint("Google登录错误: $e");
      return null;
    }
  }
}

步骤3:修改按钮点击逻辑

ElevatedButton(
  onPressed: () async {
    setState(() {
      isLoading = true;
    });
    final queryParams = await googleApi.siginwithgoogle();
    setState(() {
      isLoading = false;
    });

    if (queryParams != null && queryParams['responseType'] == 'success') {
      final token = queryParams['token'];
      // 存储token到状态管理
      profileInfoProvider.profileInfoToken(token!);
      
      // 若需用户详细信息,可携带token调用后端用户信息接口,或解析JWT payload
      // 示例:解析JWT获取用户ID
      // final payload = JwtDecoder.decode(token);
      // final userId = payload['user']['_id'];
      // profileInfoProvider.profileInfoProfileID(userId);

      // 执行后续页面跳转和数据加载
      final channelResponse = await channelApi.getAllChannels();
      channelProvider.channelListRefreshed(channelResponse.data);
      Get.offAllNamed('/wrapper');
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          behavior: SnackBarBehavior.floating,
          duration: Duration(seconds: 2),
          content: Text('Google登录失败,请重试'),
        ),
      );
    }
  },
),

步骤4:配置回调URL

  1. 在Google Cloud控制台的OAuth2客户端配置中,添加Flutter应用的回调URL(如ltp://callback或Web域名)。
  2. 确保后端FRONTEND_URL与回调URL完全一致。

关键说明

  • OAuth2授权必须通过用户交互完成,不能用后台HTTP请求直接调用授权接口。
  • 后端回调会重定向到前端并携带查询参数,Flutter端需解析这些参数获取token和登录状态。
  • 若需用户详细信息,可携带token调用后端用户信息接口,或在客户端安全解析JWT payload(注意校验签名)。

内容的提问来源于stack exchange,提问作者jayapriya durairajan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 05:31:18