将 Passport-local 的 failureRedirect 选项与 Nest.js 一起使用

发布于 2025-01-16 03:41:42 字数 2353 浏览 3 评论 0原文

我需要使用 Nest.js 进行身份验证后处理方面的帮助 使用 Nest.js 进行身份验证时,我是否在此处传递护照本地的 failureRedirect 选项?

没有 Nest.js

app.post('/login', passport.authenticate('local', {
    //Passing options here.
    successRedirect: '/',
    failureRedirect: '/login'
}));

我的代码是。 (使用 Nest.js)

local.strategy.ts

import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy } from "passport-local";
import { AuthService } from "./auth.service";

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
    constructor(private authService: AuthService) {
        super({
            //I tried passing the option here. but failed.
        })
    }

    async validate(username: string, password: string): Promise<string | null> {
        const user = this.authService.validate(username, password);
        if (!user) {
            throw new UnauthorizedException();
        }
        return user;
    }
}

local.guard.ts

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

@Injectable
export class LocalAuthGuard extends AuthGuard('local') {}

auth.controller.ts

import { Controller, Get, Post, Render, UseGuards } from "@nestjs/common";
import { LocalAuthGuard } from "./local.guard";

@Controller()
export class AuthController {
    @Get("/login")
    @Render("login")
    getLogin() {}
    
    //Redirect to '/login' when authentication failed.
    @UseGuards(LocalAuthGuard)
    @Post("/login")
    postLogin() {}
}

auth.module.ts

import { Module } from "@nestjs/common";
import { PassportModule } from "@nestjs/passport";
import { AuthController } from "./auth.controller";
import { AuthService } from "./auth.service";
import { LocalStrategy } from "./local.strategy";
import { LocalAuthGuard } from "./local.guard";

@Module({
   controllers: [AuthController],
   imports: [PassportModule],
   providers: [AuthService, LocalStrategy, LocalAuthGuard]
})
export class AuthModule {}

我尝试向 AuthController#postLogin 添加代码以在登录失败时进行重定向,但该代码似乎仅在成功登录时运行。 如果登录失败,我想使用护照本地的 failureRedirect 选项再次重定向到登录页面。

I need help with processing after authentication using Nest.js
here do I pass the failureRedirect option for passport-local when using Nest.js for authentication?

Without Nest.js

app.post('/login', passport.authenticate('local', {
    //Passing options here.
    successRedirect: '/',
    failureRedirect: '/login'
}));

My code is. (with Nest.js)

local.strategy.ts

import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy } from "passport-local";
import { AuthService } from "./auth.service";

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
    constructor(private authService: AuthService) {
        super({
            //I tried passing the option here. but failed.
        })
    }

    async validate(username: string, password: string): Promise<string | null> {
        const user = this.authService.validate(username, password);
        if (!user) {
            throw new UnauthorizedException();
        }
        return user;
    }
}

local.guard.ts

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

@Injectable
export class LocalAuthGuard extends AuthGuard('local') {}

auth.controller.ts

import { Controller, Get, Post, Render, UseGuards } from "@nestjs/common";
import { LocalAuthGuard } from "./local.guard";

@Controller()
export class AuthController {
    @Get("/login")
    @Render("login")
    getLogin() {}
    
    //Redirect to '/login' when authentication failed.
    @UseGuards(LocalAuthGuard)
    @Post("/login")
    postLogin() {}
}

auth.module.ts

import { Module } from "@nestjs/common";
import { PassportModule } from "@nestjs/passport";
import { AuthController } from "./auth.controller";
import { AuthService } from "./auth.service";
import { LocalStrategy } from "./local.strategy";
import { LocalAuthGuard } from "./local.guard";

@Module({
   controllers: [AuthController],
   imports: [PassportModule],
   providers: [AuthService, LocalStrategy, LocalAuthGuard]
})
export class AuthModule {}

I tried adding code to AuthController#postLogin to redirect on login failure, but the code seems to run only on successful login.
I would like to redirect to the login page again in case of login failure with the failureRedirect option of passport-local.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无法回应 2025-01-23 03:41:42

我找到了一个解决方法,因为遗憾的是使用护照选项不起作用:

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
  getAuthenticateOptions(context: ExecutionContext): IAuthModuleOptions {
    return {
      successReturnToOrRedirect: '/',
      failureRedirect: '/login',
    };
  }
}

相反,我创建了一个 Nestjs 过滤器来捕获包含重定向 URL 的异常。

redirecting.exception.ts

export class RedirectingException {
  constructor(public url: string) {}
}

redirecting-exception.filter.ts

import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
import { Response } from 'express';
import { RedirectingException } from './redirecting.exception';

@Catch(RedirectingException)
export class RedirectingExceptionFilter implements ExceptionFilter {
  catch(exception: RedirectingException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    response.redirect(exception.url);
  }
}

在我的验证方法中,我抛出带有正确错误消息的 RedirectingException,例如

throw new RedirectingException('/login?error="User not found"');

控制器处理其余的重定向并将错误传递给视图,以便可以显示它:

@Get('/login')
@Render('login.pug')
@Public()
async login(@Query() query) {
  return { error: query.error };
}

@Post('/login')
@Public()
@UseGuards(LocalAuthGuard)
@Redirect('/')
async doLogin() {}

我宁愿使用护照功能,包括 failureFlash,但我无法让它工作。

I found a workaround since using the passport options sadly didn't work:

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
  getAuthenticateOptions(context: ExecutionContext): IAuthModuleOptions {
    return {
      successReturnToOrRedirect: '/',
      failureRedirect: '/login',
    };
  }
}

Instead I created a Nestjs Filter to catch an exception containing a redirect URL.

redirecting.exception.ts

export class RedirectingException {
  constructor(public url: string) {}
}

redirecting-exception.filter.ts

import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
import { Response } from 'express';
import { RedirectingException } from './redirecting.exception';

@Catch(RedirectingException)
export class RedirectingExceptionFilter implements ExceptionFilter {
  catch(exception: RedirectingException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    response.redirect(exception.url);
  }
}

In my validate method I'm throwing the RedirectingException with the correct error msg, e.g.

throw new RedirectingException('/login?error="User not found"');

And the controller handles the rest of the redirecting and passes the error to the view, so it can be displayed:

@Get('/login')
@Render('login.pug')
@Public()
async login(@Query() query) {
  return { error: query.error };
}

@Post('/login')
@Public()
@UseGuards(LocalAuthGuard)
@Redirect('/')
async doLogin() {}

I'd rather use the passport functionality including the failureFlash, but I couldn't get it to work.

老子叫无熙 2025-01-23 03:41:42

在你的 PassportGuard 中你可以传递这样的东西

import {
  ExecutionContext,
  Injectable,
} from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { AuthGuard } from "@nestjs/passport";
import type { Response } from "express";
import { GithubReqUser } from "src/global/types";

@Injectable()
export class GithubAuthGuard extends AuthGuard("github") {
  constructor(private readonly configService: ConfigService) {
    super();
  }

  handleRequest<TUser = GithubReqUser["user"]>(
    err: Error | null,
    user: TUser | false,
    _info: never,
    context: ExecutionContext,
  ): TUser | void {
    const res: Response = context.switchToHttp().getResponse();

    const clientUrl = this.configService.get("allowedOrigin");

    if (err || !user) {
      return res.redirect(clientUrl + "/login");
    }

    return user;
  }
}

in your PassportGuard you can pass something like this

import {
  ExecutionContext,
  Injectable,
} from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { AuthGuard } from "@nestjs/passport";
import type { Response } from "express";
import { GithubReqUser } from "src/global/types";

@Injectable()
export class GithubAuthGuard extends AuthGuard("github") {
  constructor(private readonly configService: ConfigService) {
    super();
  }

  handleRequest<TUser = GithubReqUser["user"]>(
    err: Error | null,
    user: TUser | false,
    _info: never,
    context: ExecutionContext,
  ): TUser | void {
    const res: Response = context.switchToHttp().getResponse();

    const clientUrl = this.configService.get("allowedOrigin");

    if (err || !user) {
      return res.redirect(clientUrl + "/login");
    }

    return user;
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文