NestJS使用Passport JWT策略丢失请求



为了在我的NestJS应用程序中实现多租户,我在请求范围的提供程序中创建了数据库连接(取决于请求子域(。使用本地策略时,Passport处理的身份验证工作正常。然而,当稍后使用JWT策略时,我的连接提供商中的请求是未定义的:

ERROR [ExceptionsHandler] Cannot read property 'headers' of undefined
TypeError: Cannot read property 'headers' of undefined
at InstanceWrapper.useFactory [as metatype] (/Users/peterbienek/dev/nestjs/multitenant-typeorm/src/tenancy/tenancy.module.ts:14:29)
at Injector.instantiateClass (/Users/peterbienek/dev/nestjs/multitenant-typeorm/node_modules/@nestjs/core/injector/injector.js:304:55)
at callback (/Users/peterbienek/dev/nestjs/multitenant-typeorm/node_modules/@nestjs/core/injector/injector.js:48:41)
at processTicksAndRejections (node:internal/process/task_queues:94:5)

这是我的连接提供商:

import { Module, Scope, Global, BadRequestException } from '@nestjs/common';
import { getConnectionManager, createConnection } from 'typeorm';
import * as tenantOrmConfig from './tenant-ormconfig'
import { REQUEST } from '@nestjs/core';
const connectionFactory = {
provide: 'CONNECTION',
scope: Scope.REQUEST,
useFactory: async (req) => {
let subdomain = req.headers.host.split('.')[0]
const connectionName = subdomain
if (subdomain.indexOf('localhost') != -1 || subdomain.indexOf('127.0.0.1') != -1) {
throw new BadRequestException('Tenant code not valid')
}
const connectionManager = getConnectionManager()
const connectionPublic = connectionManager.get('default')
if (connectionManager.has(connectionName)) {
const connection = await connectionManager.get(connectionName)
return Promise.resolve(connection.isConnected ? connection : connection.connect())
}else{
console.log("CREATING CONNECTION ", connectionName)

connectionPublic.query(`CREATE SCHEMA IF NOT EXISTS ${connectionName}`)
await createConnection({
...tenantOrmConfig,
name: connectionName,
type: 'mysql',
database: connectionName,
})
const connection = await connectionManager.get(connectionName)
return Promise.resolve(connection.isConnected ? connection : connection.connect())
}

},
inject: [REQUEST]

}
@Global()
@Module({
providers: [connectionFactory],
exports: ['CONNECTION']
})
export class TenancyModule { }

JWT战略如下:

import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from '../auth.service';
import { PassportStrategy } from '@nestjs/passport';
import { ModuleRef, ContextIdFactory } from '@nestjs/core';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { SETTINGS } from 'src/app.config';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
private moduleRef: ModuleRef) {
super({
passReqToCallback: true,
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: SETTINGS.JWT_SECRET,
});
}
async validate(
payload: any, request: Request
): Promise<any> {
const contextId = ContextIdFactory.getByRequest(request);
const authService = await this.moduleRef.resolve(AuthService, contextId);
const user = await authService.validateUserByJwt(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}

本地策略(几乎相同(:

import { ModuleRef, ContextIdFactory } from '@nestjs/core';
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from '../auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {

constructor(private moduleRef: ModuleRef) {
super({passReqToCallback: true, usernameField: 'email'});
}
async validate(
request: Request,
email: string, 
password: string
): Promise<any> {
const contextId = ContextIdFactory.getByRequest(request);
const authService = await this.moduleRef.resolve(AuthService, contextId);
const user = await authService.validateUser(email, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}

使用连接的身份验证服务:

import { Scope, Injectable, Inject, NotFoundException, UnauthorizedException, BadRequestException } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { JwtPayloadService } from "./jwt.payload.service";
import { JwtPayload } from "./interfaces/jwt-payload.interface";
import { User } from "src/common/users/entities/user.entity";
import { UsersService } from "src/common/users/users.service";
import { Repository } from "typeorm";
import * as bcrypt from "bcrypt";
export class AuthService {
userRepository: Repository<User>;
constructor(
@Inject("CONNECTION") connection,
private jwtService: JwtService,
private jwtPayloadService: JwtPayloadService,
private usersService: UsersService
) {
this.userRepository = connection.getRepository(User);
}
async validateUser(email: string, pass: string): Promise<any> {
const user = await this.usersService.validate(email);
const isPasswordMatching = await bcrypt.compare(pass, user.password);
if (user && isPasswordMatching) {
const { password, ...result } = user;
return result;
}
return null;
}
async login(user: any) {
const payload = { username: user.username, sub: user.userId };
return {
access_token: this.jwtService.sign(payload),
};
}
async validateUserByJwt(payload: JwtPayload) {
console.log("payload", payload);
const user = await this.usersService.findOneByEmail(payload.email);
if (user) {
return this.jwtPayloadService.createJwtPayload(user);
} else {
throw new UnauthorizedException();
}
}
}

地方战略怎么能起作用,JWT战略怎么能不起作用?

将JwtStrategy类中的validate方法替换为:

(请求对象应为第一个参数(

async validate(
request: Request,
payload: any, 
): Promise<any> {
const contextId = ContextIdFactory.getByRequest(request);
const authService = await this.moduleRef.resolve(AuthService, contextId);
const user = await authService.validateUserByJwt(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}

相关内容

最新更新