Passportjs Google Oauth2 意外行为

问题描述 投票:0回答:1

我正在尝试使用 Nest.js - Passport.js 和 Passport-google-oauth20 实现 Login with Google (OAuth2),但面临意外行为。当它到达登录路由时 - 而不是被重定向到 Google Consent - 请求由 Google 立即完成并发送到成功回调 - (这显然是由于提前完成了同意)但成功回调似乎没有做任何事情,而是我的原始请求“使用 Google 登录”被 XHR 出错。

所以流程看起来像:

Login -> Auto Consent -> Success Callback -> [black-hole]

Front-end App Error <- original request

我不知道出了什么问题。能请你解答一下吗?

If I copy the URL the Nest.js redirects user to (like accounts.google.com/...)
and open that directly in a new tab, that prompts for the Consent and
everything works perfect as desired.

策略

@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy) {
  private logger = new Logger(GoogleStrategy.name);

  constructor(
    private authService: AuthService,
    private config: ConfigService,
  ) {
    super({
      clientID: config.getOrThrow('GOOGLE_CLIENT_ID'),
      clientSecret: config.getOrThrow('GOOGLE_CLIENT_SECRET'),
      callbackURL: config.getOrThrow('GOOGLE_CLIENT_CALLBACK'),
      scope: ['email', 'profile'],
    });
  }

  authorizationParams(): { [key: string]: string } {
    return {
      access_type: 'offline',
      prompt: 'consent',
    };
  }

  async validate(
    accessToken: string,
    refreshToken: string,
    profile: any,
    cb: (err: any, data?: any) => any,
  ): Promise<any> {
    try {
      const { name, id, emails, photos } = profile;
      const user = await this.authService.oauthFindOrCreate(
        'google',
        id,
        {
          firstName: name.givenName,
          lastName: name.familyName,
          email: emails[0].value,
          profilePicture: photos[0].value,
        },
        accessToken,
        refreshToken,
      );

      return cb(null, user);
    } catch (err) {
      this.logger.error(err);
      return cb(err);
    }
  }

  async serializeUser(user: Document, done: (err: any, id?: any) => any) {
    done(null, user._id);
  }

  async deserializeUser(id: any, done: (err: any, user?: any) => any) {
    const user = await this.authService.findById(id);
    done(null, user);
  }
}```

控制器

@Controller('auth')
export class AuthController {
  constructor(
    private authService: AuthService,
    private config: ConfigService,
  ) {}

  @Post('login/google')
  @UseGuards(AuthGuard('google'))
  oauthGoogle() {}

  @Get('login/google/success')
  @UseGuards(AuthGuard('google'))
  async oauthGoogleSuccess(
    @Auth() user: UserDocument,
    @Res({ passthrough: true }) res: Response,
  ): Promise<void> {
    const data = await this.authService.generateLogin(user);
    res.cookie('token', data.token);
    res.redirect(this.config.getOrThrow('APP_HOME'));
  }
}

请求函数(由另一个人从登录页面调用)

# Example call
req('POST', '/auth/login/google', {}, undefined, 'no-cors')
  .then(() => {
    // would not be here
  }).catch((err) => {
    // WOULD BE HERE ONCE Google redirects to /api/v1/auth/login/google/success
  });
export async function req<
  RequestData = EmptyObject | FormData,
  ResponseData = EmptyObject,
>(
  method: "POST" | "PATCH" | "PUT",
  path: string,
  data: RequestData,
  token?: string,
  mode: HttpCors = "cors",
): Promise<HttpResponse<ResponseData>> {
  return fetch(`${appConfig.apiBasePath}${path}`, {
    method,
    headers: {
      ...(data instanceof FormData
        ? {}
        : { "Content-Type": "application/json" }),

      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
    body: data instanceof FormData ? data : JSON.stringify(data),
    credentials: "include",
    mode,
  })
    .then(async (res) => {
      if (!res.ok) {
        throw (await res.json()) as ResponseData;
      }

      return res.json() as Promise<HttpResponse<ResponseData>>;
    })
    .then(
      (res: HttpResponse<ResponseData>) => res as HttpResponse<ResponseData>,
    )
    .catch((err) => {
      if (err?.statusCode && err?.message) {
        throw err;
      }

      throw { statusCode: 500, message: "Something went wrong!", error: true };
    });
}
node.js google-oauth passport.js
1个回答
0
投票

实际上,我正在使用

XHR
方法向登录路由发出
POST
请求 - 虽然它应该是对登录路由的直接 GET 请求,从该请求将发起到 OAuth 服务器并分别返回到服务器和 API 服务器确实负责引导用户登录后正确的页面。

我能够发现这个问题 - 它太愚蠢但足够微妙,以至于花了我几个小时。我现在不知道更深入的细节,但仍然发布答案,以便如果有人遇到这种情况。

如果其他人可以解释实际行为 - 这将非常有帮助 - 所以仍然会寻找更好的答案。

© www.soinside.com 2019 - 2024. All rights reserved.