在NestJS中实现多ClientID/Secret的Passport谷歌、Facebook认证
实现NestJS多应用动态Passport认证(Google/Facebook)
核心需求
通过请求参数appID匹配数据库中对应应用的OAuth配置(clientID、clientSecret、callbackURL等),让不同应用使用专属密钥完成Google/Facebook认证。
具体实现方案
1. 自定义动态AuthGuard
替换默认AuthGuard,实现从请求中获取appID并动态加载应用配置:
import { Injectable, ExecutionContext } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { AuthService } from './auth.service'; @Injectable() export class DynamicGoogleAuthGuard extends AuthGuard('google') { constructor(private readonly authService: AuthService) { super(); } async canActivate(context: ExecutionContext): Promise<boolean> { const request = context.switchToHttp().getRequest(); const appID = request.query.appID; // 从数据库查询对应应用的Google OAuth配置 const oauthConfig = await this.authService.getAppOAuthConfig(appID, 'google'); // 动态覆盖Passport认证配置 this.authenticate(request, { clientID: oauthConfig.clientID, clientSecret: oauthConfig.clientSecret, callbackURL: oauthConfig.callbackURL, scope: oauthConfig.scope || ['email', 'profile'], }); return super.canActivate(context); } }
2. 调整GoogleStrategy为基础策略
移除硬编码配置,保留基础逻辑:
import { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy, VerifyCallback } from 'passport-google-oauth20'; @Injectable() export class GoogleStrategy extends PassportStrategy(Strategy, 'google') { constructor() { super({ scope: ['email', 'profile'], // 默认权限,可被动态覆盖 }); } async validate( accessToken: string, refreshToken: string, profile: any, done: VerifyCallback, ): Promise<any> { // 可根据appID和用户信息完成关联逻辑 const user = { email: profile.emails[0].value, firstName: profile.name.givenName, lastName: profile.name.familyName, avatar: profile.photos[0].value, accessToken, }; done(null, user); } }
3. 控制器使用自定义Guard
更新控制器,替换为动态Guard:
import { Controller, Get, Req, Query } from '@nestjs/common'; import { UseGuards } from '@nestjs/common'; import { DynamicGoogleAuthGuard } from './dynamic-google-auth.guard'; import { GoogleAuthService } from './google-auth.service'; @Controller('google-auth') export class GoogleAuthController { constructor(private readonly googleAuthService: GoogleAuthService) {} @Get('login') @UseGuards(DynamicGoogleAuthGuard) login(@Query('appID') appID: string) {} @Get('redirect') @UseGuards(DynamicGoogleAuthGuard) redirect(@Req() req) { return this.googleAuthService.handleAuthSuccess(req.user); } @Get('status') status() {} @Get('logout') logout() {} }
4. 实现配置查询服务
创建AuthService负责从数据库读取应用OAuth配置:
import { Injectable, NotFoundException } from '@nestjs/common'; import { AppRepository } from './app.repository'; @Injectable() export class AuthService { constructor(private readonly appRepository: AppRepository) {} async getAppOAuthConfig(appID: string, provider: 'google' | 'facebook') { const app = await this.appRepository.findOne({ where: { id: appID } }); if (!app) throw new NotFoundException('应用不存在'); const config = app.oauthConfigs[provider]; if (!config) throw new NotFoundException('该应用未配置对应认证服务'); return config; } }
5. 模块注入依赖
确保所有组件被正确注入:
import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; import { GoogleStrategy } from './google.strategy'; import { GoogleAuthController } from './google-auth.controller'; import { GoogleAuthService } from './google-auth.service'; import { DynamicGoogleAuthGuard } from './dynamic-google-auth.guard'; import { AuthService } from './auth.service'; import { AppRepository } from './app.repository'; @Module({ imports: [PassportModule], controllers: [GoogleAuthController], providers: [ GoogleStrategy, GoogleAuthService, DynamicGoogleAuthGuard, AuthService, AppRepository, ], }) export class AuthModule {}
Facebook认证复用逻辑
只需复制上述流程:
- 创建
FacebookStrategy继承PassportStrategy(Strategy, 'facebook') - 实现
DynamicFacebookAuthGuard,查询配置时指定provider: 'facebook' - 控制器对应接口使用
DynamicFacebookAuthGuard
内容的提问来源于stack exchange,提问作者umer jamal
相关产品推荐
相关产品推荐

