nestjs / docs.nestjs.com

The official documentation https://docs.nestjs.com 📕
MIT License
1.2k stars 1.74k forks source link

Basic authentication from documentation does not work #838

Closed viniciusgati closed 5 years ago

viniciusgati commented 5 years ago

Bug Report

Current behavior

Following the examples from documentation for authentication i got 2 problems.

  1. Passport returned:
[Nest] 27924   - 2019-11-14 15:16:06   [ExceptionHandler] Authentication strategies must have a name +3ms
Error: Authentication strategies must have a name
    at Authenticator.use (C:\Users\Vinicius\Code\dms-2\node_modules\passport\lib\authenticator.js:56:22)
    at new MixinStrategy (C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\passport\dist\passport\passport.strategy.js:35:26)
    at new LocalStrategy (C:\Users\Vinicius\Code\dms-2\dist\shared\auth\local.strategy.js:18:9)
    at Injector.instantiateClass (C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\core\injector\injector.js:277:19)
    at callback (C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\core\injector\injector.js:74:41)
    at process._tickCallback (internal/process/next_tick.js:68:7)

I solved this with:

export class LocalStrategy extends PassportStrategy(Strategy, "local") {

instead of

export class LocalStrategy extends PassportStrategy(Strategy) {
  1. having the controller like:
import { Controller, Request, UseGuards, Post } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";

@Controller("auth")
export class AuthController {
  @UseGuards(AuthGuard("local"))
  @Post("login")
  async login(@Request() req) {
    return req.user;
  }
}

and doin a request for this controlle with login and password throws:

[Nest] 5348   - 2019-11-14 15:18:36   [ExceptionsHandler] Strategy#authenticate must be overridden by subclass +38758ms
Error: Strategy#authenticate must be overridden by subclass
    at LocalStrategy.Strategy.authenticate (C:\Users\Vinicius\Code\dms-2\node_modules\passport-strategy\lib\strategy.js:21:9)
    at attempt (C:\Users\Vinicius\Code\dms-2\node_modules\passport\lib\middleware\authenticate.js:361:16)
    at authenticate (C:\Users\Vinicius\Code\dms-2\node_modules\passport\lib\middleware\authenticate.js:362:7)
    at Promise (C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\passport\dist\auth.guard.js:83:3)
    at new Promise (<anonymous>)
    at C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\passport\dist\auth.guard.js:75:83
    at MixinAuthGuard.<anonymous> (C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\passport\dist\auth.guard.js:47:36)
    at Generator.next (<anonymous>)
    at C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\passport\dist\auth.guard.js:19:71
    at new Promise (<anonymous>)
    at __awaiter (C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\passport\dist\auth.guard.js:15:12)
    at MixinAuthGuard.canActivate (C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\passport\dist\auth.guard.js:40:20)
    at GuardsConsumer.tryActivate (C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\core\guards\guards-consumer.js:14:34)
    at canActivateFn (C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\core\router\router-execution-context.js:132:59)
    at C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\core\router\router-execution-context.js:41:37
    at C:\Users\Vinicius\Code\dms-2\node_modules\@nestjs\core\router\router-proxy.js:8:23

This error i am not being able to solve.

Expected behavior

Possible Solution

Environment


Nest version: 6.7.2

For Tooling issues:
- Node version: 10.13.0
- Platform:  Windows

Others:
using yarn

dependencies:
```
    "@nestjs/common": "^6.7.2",
    "@nestjs/core": "^6.7.2",
    "@nestjs/mongoose": "^6.1.2",
    "@nestjs/passport": "^6.1.0",
    "@nestjs/platform-express": "^6.7.2",
    "class-transformer": "^0.2.3",
    "class-validator": "^0.11.0",
    "dotenv": "^8.2.0",
    "express-rate-limit": "^5.0.0",
    "helmet": "^3.21.2",
    "mongoose": "^5.7.10",
    "passport": "^0.4.0",
    "passport-http-bearer": "^1.0.1",
    "passport-local": "^1.0.0",
    "redis": "^2.8.0",
    "reflect-metadata": "^0.1.13",
    "rimraf": "^3.0.0",
    "rxjs": "^6.5.3",
    "simple-node-logger": "^18.12.23"
```            
johnbiundo commented 5 years ago

@viniciusgati can you provide a basic repo to reproduce this?

viniciusgati commented 5 years ago

Here it goes @johnbiundo thanks for your help.

joeyslack commented 5 years ago

I took a look at your repo, and there a few things wrong.

First, you need an auth service. See https://docs.nestjs.com/techniques/authentication#implementing-passport-strategies. Often times an auth.service would inject a UsersModule dependency, as to resolve authentication against users. You don't have a user service in your project, so we'll skip that detail.

Second, as far as the AuthController is concerned, you'll need to fix up your auth.module. Remove your controller line, and include your newly created AuthService to your providers list: providers: [AuthService]. Remove the controller injection in the module.

You'll want to use the @AuthGuard on any controller route in your project that you want guarded, and then your AuthService will handle the logic (often times the AuthService would check against a UserService:authCheck kind of method). You'll need to create a users module if you want to go that route, but you can always authenticate against anything else, not just users, so we'll keep this advice generic for now.

viniciusgati commented 5 years ago

the auto-import used

import { Strategy } from 'passport-strategy';

instead of

import { Strategy } from 'passport-local';

primary-byte commented 3 years ago

@viniciusgati You are a god amongst men. Thank you sir!!

vansham-gortnm commented 3 years ago

I am facing the same issue. I tried to replicate the example in a simple form though. It seems the AuthGuard isn't doing anything at all. Also using a custom guard isn't working too.

Auth.module.ts

import { Module } from "@nestjs/common";
import { PassportModule } from "@nestjs/passport";
import { SessionSerializer } from "./serializer/serializer";
import { LocalStrategy } from './strategies/local.strategy'

@Module({
    imports: [PassportModule],
    providers: [LocalStrategy, SessionSerializer],
    exports: [PassportModule]
})
export class AuthModule {

}

LocalStrategy.ts

import { Strategy, IStrategyOptions } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport'
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
    constructor() {
        const options: IStrategyOptions = {
            session: true
        }
        super(options)
    }

    async validate(username: string, password: string) {
        const user = "vansham"
        console.log("VERIFY CALLBACK >>>")

        if (username !== user)
            throw new HttpException("wrong username ", HttpStatus.UNAUTHORIZED);

        return user

    }

}

Login Guard

import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport'

@Injectable()
export class LoginGuard extends AuthGuard('local') {
    async canActivate(context: ExecutionContext) {
        console.log("LOGIN GUARD ACTIVTAED >> ")
        const result = (await super.canActivate(context)) as boolean;
        console.log("LOGIN GUARD RESULT >>", result)
        const request = context.switchToHttp().getRequest();
        await super.logIn(request)
        console.log("LOGIN GUARD RESULT >>", result)
        return result;

    }
}

app.controller.ts

import { Controller, Get, Post, Req, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Request } from 'express';
import { LoginGuard } from 'src/Guards/loginGuard';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('root.get')
  getHello(): string {
    return this.appService.getHello();
  }

  @UseGuards(LoginGuard)
  @Post('login')
  login(@Req() req: Request) {
    console.log("LOGIN ROUTE", req.body)
    return "HI"
  }
}

It just returns me unauthorized. It's a struggle everyday with nest. SMH

jmcdo29 commented 3 years ago

@vansham-gortnm if you're looking for support, I suggest you try out Discord channel. The authentication setup in the docs has successfully worked for others, so I do not believe this to be a bug.

mondyfy commented 3 years ago

In my case auto import used import { Strategy } from 'passport';

instead of

import { ExtractJwt, Strategy } from 'passport-jwt';