typescript - დაუშვებელი 401 (ვალიდური მონაცემების ნაკლებობა) Passport JWT-ის გამოყენებით NestJS-ში


მეც ვცდილობ JWT-ს გამოყენებას, რათა ავთენტიფიცირებული გავხადო ჩემი მომხმარებლები ჩემს NestJS API-ში, მაგრამ ყოველთვის მივიღებ ერთსა და იმავე შეცდომას: Unauthorized 401.

განვმარტავ ჩემს კოდს, სანამ გითხრათ ჩემი გამოძიება, რომელიც უშედეგო აღმოჩნდა:

JWT-ის გენერაცია (ეს კოდი სწორად მუშაობს)

auth.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import { UserModule } from 'src/user/user.module';
import { AuthService } from './auth.service';
import { LocalAuthController } from './local/local-auth.controller';
import { JwtStrategy } from './jwt/jwt.strategy';

@Module({
    imports: [
        ConfigModule,
        JwtModule.register({
            secretOrPrivateKey: 'a'
        }),
        UserModule],
    providers: [AuthService, JwtStrategy],
    controllers: [LocalAuthController]
})
export class AuthModule {}

auth.service.ts

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UserService } from 'src/user/user.service';
import * as bcrypt from 'bcrypt';
import { LocalAuthDto } from './local/local-auth.dto';
import { AccountType, User } from 'src/user/entity/user.entity';
import { JwtPayload } from './jwt/jwt.payload';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
    constructor(
        private readonly userService: UserService,
        private readonly jwtService: JwtService,
    ) {}

    async signinLocal(localAuthDto: LocalAuthDto): Promise<any | null> {
        const user = await this.userService.findOneByEmailOrUsername(localAuthDto.emailOrUsername, true);

        if (user === null || !(await bcrypt.compare(localAuthDto.password, user.password)))
            throw new UnauthorizedException("Invalid credentials");

        const payload: JwtPayload = { sub: user.uuid };

        return this.jwtService.sign(payload);
    }
}

ლოკალური-მომხმარებლის-ავტორიზაცია.controller.ts

import { Body, Controller, Post, Request, UnauthorizedException, UseGuards } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AuthService } from '../auth.service';
import { LocalAuthDto } from './local-auth.dto';

@ApiTags("auth")
@Controller('auth/local')
export class LocalAuthController {

    constructor(private readonly authService: AuthService) {}

    @Post('signin')
    async signin(@Body() localAuthDto: LocalAuthDto) {
        return await this.authService.signinLocal(localAuthDto);
    }
}

jwt.payload.ts

export class JwtPayload {
    sub: string;
}

JWT გამოყენება (ეს არ მუშაობს)

jwt.strategy.ts

import { Injectable, Logger, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { ExtractJwt } from "passport-jwt";
import { Strategy } from "passport-local";

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
    constructor() {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: true,
            secretOrKey: 'a',
        });
    }

    async validate(payload: any) {
        return payload;
    }
}

jwt.guard.ts

import { Injectable, Logger, UnauthorizedException } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
    private readonly logger = new Logger(JwtAuthGuard.name);

    handleRequest(err, user, info) {
        this.logger.error(err, user, info);
        
        if (err || !user) {
            throw err || new UnauthorizedException();
        }
        return user;
    }

}

სად ვიყენებ JwtAuthGuard

აპპი.კონტროლერი.ts

import { Controller, Get, UseGuards } from '@nestjs/common';
import { ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard as JwtAuthGuard } from './auth/jwt/jwt.guard';

@Controller()
export class AppController {
    constructor() {}

    @Get()
    healthCheck(): string {
        return "API started";
    }

    @ApiBearerAuth()
    @UseGuards(JwtAuthGuard)
    @Get("authCheck")
    authenticationGuardCheck(): string {
        return "It works";
    }

}

ჩემი გამოძიება

პირველად დავიმუშავე გენერირებული JWT ჩემი კოდის მიერ: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIwNGRkM2MyNi03YjA4LTQ2MWEtYTA4OS05YWRkOTgzZjZmODUiLCJpYXQiOjE2NzA3NzU2MzR9.0MuojBY0_i5Losa6IgPrB2A2py-XrLoueMc4Mk1PUrY მასში არის სწორი uuid და კარგად არის ხელმოწერილი საიდუმლოთი: a

პასპორტმა კონსოლში არ დამინახა შეცდომები და უბრალოდ დამიბრუნა Unauthorized 401

ასევე დავწინასწარმეტყველე უფრო მეტი ინფორმაცია და ვიპოვე ეს კოდი (jwt.guard.ts-ში):

handleRequest(err, user, info) {
        this.logger.error(err, user, info);
        
        if (err || !user) {
            throw err || new UnauthorizedException();
        }
        return user;
    }

ახლა, როცა მოთხოვნას ვუგზავნი, კონსოლში ეს მივიღე: passport „შეცდომები“

ასე რომ, მე ვთხოვ NestJS-ს დაბეჭდოს ჩემი მოთხოვნები და ჩემი ტოკენი არის: მოთხოვნის სათაური

და ახლა მე აქ დავრჩი, ვერ ვხვდები რატომ ვერ იღებს პასპორტი ჩემს ტოკენს მოთხოვნის სათაურებიდან. შენ ჩემი ბოლო შანსი ხარ ;(

გმადლობთ დახმარებისთვის

პასუხი #1

თქვენს JwtStrategy-ში თქვენ იმპორტობთ Strategy-ს passport-local-დან passport-jwt-ის ნაცვლად. ეს ნიშნავს, რომ passport ეძებს req.body.username და req.body.password-ს, ნაცვლად იმისა, რომ ყურადღება მიაქციოს იმ JWT-ს, რომელსაც თქვენ გზავნით authorization სათაურის საშუალებით. იმპორტეთ Strategy passport-jwt-დან და ეს უნდა გადაწყდეს.