Nano Hash - криптовалюты, майнинг, программирование

Nest.js Auth Guard JWT Authentication постоянно возвращает 401 неавторизованный

Используя Postman для тестирования своих конечных точек, я могу успешно войти в систему и получить токен JWT. Теперь я пытаюсь подключиться к конечной точке, которая предположительно имеет AuthGuard, чтобы убедиться, что теперь, когда я вошел в систему, я могу получить к ней доступ.

Однако он постоянно возвращает 401 Unauthorized, даже если представлен токен JWT в Postman.

Вот мой код:

user.controller.ts

@Controller('users')
export class UsersController {
    constructor(private readonly usersService: UsersService) {}

    @UseGuards(AuthGuard())
    @Get()
    getUsers() {
        return this.usersService.getUsersAsync();
    }
}

jwt.strategy.ts

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor(
        private readonly authenticationService: AuthenticationService,
    ) {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: false,
            secretOrKey: 'SuperSecretJWTKey',
        });
    }

    async validate(payload: any, done: Function) {
        console.log("I AM HERE"); // this never gets called.
        const user = await this.authenticationService.validateUserToken(payload);

        if (!user) {
            return done(new UnauthorizedException(), false);
        }

        done(null, user);
    }
}

Я тоже пробовал ExtractJWT.fromAuthHeaderWithScheme('JWT'), но это не сработало.

authentication.module.ts

@Module({
    imports: [
        ConfigModule,
        UsersModule,
        PassportModule.register({ defaultStrategy: 'jwt' }),
        JwtModule.register({
            secret: 'SuperSecretJWTKey',
            signOptions: { expiresIn: 3600 },
        }),
    ],
    controllers: [AuthenticationController],
    providers: [AuthenticationService, LocalStrategy, JwtStrategy],
    exports: [AuthenticationService, LocalStrategy, JwtStrategy],
})
export class AuthenticationModule {}

authentication.controller.ts

@Controller('auth')
export class AuthenticationController {
    constructor(
        private readonly authenticationService: AuthenticationService,
        private readonly usersService: UsersService,
    ) {}

    @UseGuards(AuthGuard('local'))
    @Post('login')
    public async loginAsync(@Response() res, @Body() login: LoginModel) {
        const user = await this.usersService.getUserByUsernameAsync(login.username);

        if (!user) {
            res.status(HttpStatus.NOT_FOUND).json({
                message: 'User Not Found',
            });
        } else {
            const token = this.authenticationService.createToken(user);
            return res.status(HttpStatus.OK).json(token);
        }
    }
}

В Postman я могу использовать свою конечную точку входа для успешного входа в систему с соответствующими учетными данными и получения токена JWT. Затем я добавляю заголовок Authentication в запрос GET, копирую и вставляю токен JWT, и я пробовал схемы на предъявителя и JWT, и обе возвращают 401 Unauthorized, как вы можете видеть на изображениях ниже.

введите описание изображения здесь

введите описание изображения здесь

Я использовал отладчик JWT.IO, чтобы проверить, что с моим токеном что-то не так, и он кажется правильным: введите описание изображения здесь

Я не понимаю, в чем может быть проблема. Любая помощь будет принята с благодарностью.


  • Проблема может быть в вашем запросе от почтальона. Попробуйте создать новый запрос и будьте осторожны при размещении в заголовках. Если вы используете токен-носитель, поместите его в раздел аутентификации, а не в заголовки. Или поместите его в заголовки, а не в раздел авторизации. Проведите несколько экспериментов, это может помочь. 31.01.2021

Ответы:


1

Обратите внимание, что функция validate() в вашей стратегии JWT вызывается только после успешной проверки JWT. Если вы постоянно получаете ответ 401 при попытке использовать JWT, вы не можете ожидать, что эта функция будет вызвана.

return из метода validate() вводится в объект запроса любой операции, защищенной аутентификацией JWT.

Я не уверен насчет функции done(), которую вы вызываете, но вот рабочий метод validate() из моего текущего проекта:

async validate(payload: JwtPayload): Promise<User> {
  const { email } = payload
  const user = await this.authService.getActiveUser(email)

  if (!user) {
    throw new UnauthorizedException()
  }

  return user
}

Похоже, вы на правильном пути, желая вернуть пользователя. Убедитесь, что это действительно то, что делает authenticationService.validateUserToken().

В стратегии jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken() кажется правильным, а в Postman, использующем заголовок авторизации с Bearer TOKEN, также выглядит правильным.

Что касается вашего authentication.controller.ts файла, будьте осторожны при использовании объектов @Request и @Response непосредственно в ваших контроллерах в NestJS. Они получают доступ к базовой структуре, например Express и могут обойти многие функции, реализованные Nest. См. https://docs.nestjs.com/faq/request-lifecycle, чтобы посмотрите, что вы пропускаете ...

Вы можете возвращать объекты и выдавать ошибки непосредственно из метода декорированного контроллера (например, @Get(), Post() и т. Д.) В NestJS, а фреймворк позаботится обо всем остальном: код HTTP, JSON и т. Д.

Из вашего контроллера рассмотрите возможность отказа от @Reponse res и использования вместо этого throw new UnauthorizedException('User Not Found') и простого return { token } (или аналогичного) подхода.

В вашем защищенном маршруте я обнаружил, что явное объявление AuthGuard('jwt') работает лучше и в некоторых случаях не вызывает предупреждений, даже если вы установили стратегию по умолчанию как JWT.

Вам действительно нужен AuthGuard('local') на вашем маршруте входа?

Внутри вашего loginAsync() метода НЕ забывайте о важном шаге, который фактически подписывает ваш токен полезной нагрузкой. Вы не предоставили свой код для реализации метода createToken() в своей службе аутентификации, но я подозреваю, что это может быть то, что вам не хватает.

Рассмотрим эту рабочую реализацию службы входа в систему (которая просто вызывается функцией входа в систему контроллера):

  async login(authCredentialsDto: AuthCredentialsDto): Promise<{ accessToken: string }> {
    const { email, password } = authCredentialsDto

    const success = await this.usersRepository.verifyCredentials(email, password)

    if (!success) {
      throw new UnauthorizedException('Invalid credentials')
    }

    // roles, email, etc can be added to the payload - but don't add sensitive info!
    const payload: JwtPayload = { email } 
    const accessToken = this.jwtService.sign(payload)

    this.logger.debug(`Generated JWT token with payload ${JSON.stringify(payload)}`)

    return { accessToken }
  }

Обратите внимание, что jwtService вводится в класс через внедрение зависимостей путем добавления private jwtService: JwtService в параметры конструктора.

Также обратите внимание на то, как в приведенном выше описании определяется интерфейс для JwtPayload, поэтому он явно типизирован. Это лучше, чем использовать any в вашем коде.

Наконец, если ваш JWT по-прежнему не проходит проверку, абсолютно уверены в том, что вы правильно используете свой токен в Postman. Будьте предельно осторожны, чтобы не добавлять начальные / конечные пробелы, новые строки и т. Д. Я сам допустил эту ошибку. Вы можете проверить работоспособность, написав быстрый JS-файл, чтобы опробовать ваш API и сделать запрос на выборку, который устанавливает заголовок авторизации со значением Bearer ${token}.

Надеюсь, это поможет, удачи!

08.07.2020
  • Спасибо. Это было большим подспорьем. Произошло то, что я использовал пакет с именем jsonwebtoken и делал что-то вроде import * as jwt from 'jsonwebtoken', за которым следовало jwt.sign(...). При использовании фактического JwtService от @nestjs/jwt это исправило. 09.07.2020
  • Я рад, что это помогло, конечно, использование фактического @nestjs/jwt - это способ пойти с этим подходом! Ваше здоровье! 09.07.2020

  • 2

    У меня была точно такая же проблема. Моя проблема заключалась в том, что JwtModule secret и JwtStrategy secretOrKey были разными. Надеюсь, это поможет кому-то застрять в этом!

    03.10.2020
  • У меня точно такая же проблема! Связано с неправильной загрузкой .env. Это третья проблема, связанная с этим, которую я заметил и до сих пор не могу понять. 06.11.2020
  • спасибо, я не знаю, как я это пропустил 25.12.2020

  • 3

    У меня был аналогичный статус 401. Моя проблема заключалась в том, что срок действия токена был очень коротким (60 секунд). Убедитесь также, что у вас есть разумный срок действия при тестировании jwt.

    25.11.2020
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..