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

如何在NestJS谷歌登录URL传递查询参数并在回调中使用

解决NestJS谷歌认证中传递查询参数到回调的问题

要实现从登录触发URL传递查询参数到回调方法,核心是利用OAuth2的state参数携带自定义数据,通过重写Guard捕获参数、在Strategy中解析传递,最终在回调方法中使用。

步骤1:重写GoogleAuthGuard捕获查询参数

修改Guard类,重写getAuthenticateOptions方法,从请求中提取需要传递的查询参数,封装到state中(谷歌OAuth会原封不动将state带回回调):

import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ExecutionContext } from '@nestjs/common';

@Injectable()
export class GoogleAuthGuard extends AuthGuard('google') {
  getAuthenticateOptions(context: ExecutionContext) {
    const request = context.switchToHttp().getRequest();
    // 示例捕获`redirectTo`参数,可替换为你需要的参数名
    const customParams = {
      redirectTo: request.query.redirectTo,
      // 可添加更多自定义参数
    };
    // 转成JSON字符串存入state,敏感参数建议加密
    return { state: JSON.stringify(customParams) };
  }
}

步骤2:修改GoogleStrategy接收并传递参数

更新Strategy的validate方法,从回调请求中获取谷歌带回的state,解析后和用户信息一起返回,供后续回调方法使用:

import { PassportStrategy } from '@nestjs/passport';
import { Strategy, Profile, VerifiedCallback } from 'passport-google-oauth20';
import { ConfigService } from '@nestjs/config';
import { ConfigEnum } from '../config/enum/config.enum';
import { Request } from 'express';

export class GoogleStrategy extends PassportStrategy(Strategy) {
  constructor(private configService: ConfigService) {
    super({
      clientID: configService.get(ConfigEnum.CLIENT_ID),
      clientSecret: configService.get(ConfigEnum.CLIENT_SECRET),
      callbackURL: configService.get('CALLBACK_URL'),
      scope: ['profile', 'email'],
      passReqToCallback: true, // 开启后可获取请求对象
    });
  }

  async validate(
    req: Request,
    accessToken: string,
    refreshToken: string,
    profile: Profile,
    done: VerifiedCallback,
  ): Promise<any> {
    const email = profile.emails[0].value;
    // 解析谷歌带回的state,获取自定义参数
    const state = req.query.state as string;
    const customParams = JSON.parse(state);

    // 将用户信息和自定义参数一起返回
    done(null, { email, ...customParams });
  }
}

步骤3:在回调方法中使用参数

修改回调控制器方法,从req.user中提取传递过来的查询参数并使用:

import { Get, Req, Res, UseGuards } from '@nestjs/common';
import { Response, Request } from 'express';
import { GoogleAuthGuard } from './google-auth.guard';
import { AuthService } from './auth.service';

@Get('google/login')
@UseGuards(GoogleAuthGuard)
handleGoogleLogin() {}

@Get('google/redirect')
@UseGuards(GoogleAuthGuard)
async handleGoogleRedirect(@Req() req: Request, @Res() res: Response) {
  // 从req.user中获取自定义参数和用户信息
  const { email, redirectTo } = req.user as any;
  const tokens = await this.authService.signInWithGoogle(req);

  // 使用自定义参数,比如跳转到指定地址
  const targetUrl = redirectTo 
    ? `${redirectTo}?tokens=${tokens}` 
    : 'http://localhost:8080?tokens=' + tokens;
  
  res.redirect(302, targetUrl);
}

步骤4:配置Session中间件

Passport需要Session存储认证临时数据,在main.ts中添加Session配置:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as session from 'express-session';
import * as passport from 'passport';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  // 配置Session,生产环境请更换密钥并开启secure cookie
  app.use(session({
    secret: 'your-session-secret-key',
    resave: false,
    saveUninitialized: false,
    cookie: { 
      secure: process.env.NODE_ENV === 'production',
      maxAge: 3600000 // 1小时有效期
    },
  }));
  
  app.use(passport.initialize());
  app.use(passport.session());

  await app.listen(3000);
}
bootstrap();

安全提示

如果传递敏感参数,建议对state进行加密处理,避免参数被篡改或泄露。可使用Node.js的crypto模块实现AES加密解密。

内容的提问来源于stack exchange,提问作者Chandradeep Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 18:35:16