Nest.js中Github OAuth2与JWT共存时req.user未定义问题
Nest.js passport-github2认证回调中req.user为undefined的问题
我已在Nest.js中实现JWT认证,当前使用passport-github2做Github第三方认证时遇到问题:Github认证的回调接口里,req.user始终为undefined。
通过日志确认,github.strategy.ts中的validateGithubUser方法已成功找到或创建user对象,但该对象并未传递到请求中。我需要在githubAuthCallback方法中获取到非undefined的req.user。
以下是相关代码:
github.strategy.ts
import { Injectable, Logger } from '@nestjs/common'; import { AppConfig } from '@/lib/config/config.provider'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy, Profile, StrategyOptionsWithRequest, } from 'passport-github2'; import { AuthenticationService } from '../authentication.service'; import { Request } from 'express'; type VerifyCallback = (error: any, user?: any, info?: any) => void; const githubOptions: StrategyOptionsWithRequest = { clientID: AppConfig.authentication.GITHUB_CLIENT_ID, clientSecret: AppConfig.authentication.GITHUB_CLIENT_SECRET, callbackURL: AppConfig.authentication.GITHUB_CALLBACK_URL, passReqToCallback: true, scope: ['user:email'], }; @Injectable() export class GithubStrategy extends PassportStrategy(Strategy, 'github') { private readonly logger = new Logger(GithubStrategy.name); constructor(private readonly authService: AuthenticationService) { super(githubOptions); } async validate( req: Request, accessToken: string, _refreshToken: string, profile: Profile, done: VerifyCallback, ): Promise<any> { try { console.log('GitHub Profile:', profile); const user = await this.authService.validateGithubUser(profile); console.log('User object from AuthService:', user); if (!user) { console.log('No user found'); return done(null, false); } console.log('User object passed to done callback:', user); return done(null, user); } catch (err) { this.logger.error('Failed to validate github authentication', { error: err, }); throw new Error(err); } } }
github.guard.ts
import { ExecutionContext, Injectable, UnauthorizedException, } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @Injectable() export class GithubAuthGuard extends AuthGuard('github') { canActivate(context: ExecutionContext) { return super.canActivate(context); } // eslint-disable-next-line @typescript-eslint/no-unused-vars handleRequest(err, user, _info) { if (err || !user) { throw err || new UnauthorizedException(); } return user; } }
authentication.module.ts
import { Global, Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; import { EventEmitterModule } from '@nestjs/event-emitter'; import { JwtModule } from '@nestjs/jwt'; import { AuthenticationController } from './authentication.controller'; import { AuthenticationService } from './authentication.service'; import { LocalStrategy } from './strategies/local.strategy'; import { AccessTokenJwtStrategy } from './strategies/access-token.strategy'; import { AppEventHandler } from '@/common/events/app.events'; import { GithubStrategy } from './strategies/github.strategy'; @Global() @Module({ imports: [ PassportModule.register({ defaultStrategy: ['jwt', 'github'], session: false, }), JwtModule.register({}), EventEmitterModule.forRoot(), ], controllers: [AuthenticationController], providers: [ AuthenticationService, LocalStrategy, AccessTokenJwtStrategy, GithubStrategy, AppEventHandler, ], exports: [AuthenticationService], }) export class AuthenticationModule {}
auth.controller.ts
@UseGuards(GithubAuthGuard) @Get('/auth/github') public githubAuth() {} @UseGuards(GithubAuthGuard) @Get('/auth/github/callback') public async githubAuthCallback(@Req() req: Request) { const user = req.user; console.log('User object in controller:', user); if (!user) { return { message: 'Authentication failed' }; } return { message: 'Authentication successful', user: user }; }
问题排查与解决
1. 修复Passport模块配置冲突
Github OAuth2认证依赖临时会话存储state参数,你当前关闭了session会导致认证状态丢失,进而无法传递user对象。修改PassportModule配置:
// authentication.module.ts PassportModule.register({ defaultStrategy: 'jwt', // 默认用JWT,Github认证通过守卫单独指定 session: true, // 开启session支持Github OAuth流程 }),
2. 修正Validate方法的错误处理
validate方法中直接抛出异常会中断Passport流程,需改用done回调传递错误:
// github.strategy.ts async validate( req: Request, accessToken: string, _refreshToken: string, profile: Profile, done: VerifyCallback, ): Promise<any> { try { console.log('GitHub Profile:', profile); const user = await this.authService.validateGithubUser(profile); console.log('User object from AuthService:', user); if (!user) { console.log('No user found'); return done(null, false); } console.log('User object passed to done callback:', user); return done(null, user); } catch (err) { this.logger.error('Failed to validate github authentication', { error: err, }); // 用done回调传递错误,而非抛出异常 return done(err, null); } }
3. 启用Express会话中间件
Nest.js默认不包含会话中间件,需手动安装配置:
- 安装依赖:
npm install express-session
- 在
main.ts中添加中间件:
import * as session from 'express-session'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 会话中间件需放在其他中间件之前 app.use( session({ secret: 'your-secure-secret-key', // 替换为安全密钥 resave: false, saveUninitialized: false, cookie: { secure: process.env.NODE_ENV === 'production' }, // 生产环境启用HTTPS }), ); await app.listen(3000); } bootstrap();
4. 验证回调URL一致性
检查Github开发者后台配置的回调URL,确保与AppConfig.authentication.GITHUB_CALLBACK_URL完全一致(包括协议、路径、端口)。
完成以上修改后重启服务,测试Github认证流程即可在回调接口中获取到req.user。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

