NodeJS nestjs中的可选身份验证

lx0bsm1f  于 2023-05-17  发布在  Node.js
关注(0)|答案(3)|浏览(141)

我想知道是否有一个装饰器,使req.user对象在控制器方法中可用,如果用户登录(Authauization头发送),如果没有,那么就让req.user为null。
如果用户没有登录,AuthGuard装饰器将返回401,所以它不适合我的情况。

toiithl6

toiithl61#

没有内置的装饰器,但您可以轻松地自己创建一个。请参阅docs的示例:

import { createParamDecorator } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

export const User = createParamDecorator((data, req) => {
  return req.user;
});

由于内置的AuthGuard会抛出异常,因此您可以创建自己的版本并覆盖请求处理程序:

@Injectable()
export class MyAuthGuard extends AuthGuard('jwt') {

  handleRequest(err, user, info) {
    // no error is thrown if no user is found
    // You can use info for logging (e.g. token is expired etc.)
    // e.g.: if (info instanceof TokenExpiredError) ...
    return user;
  }

}

请确保您没有在JwtStrategy中抛出错误:

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authService: AuthService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: 'secretKey',
    });
  }

  async validate(payload) {
    const user = await this.authService.validateUser(payload);
    // in the docs an error is thrown if no user is found
    return user;
  }
}

然后你可以像这样在Controller中使用它:

@Get()
@UseGuards(MyAuthGuard)
getUser(@User() user) {
  return {user};
}
wydwbb8l

wydwbb8l2#

另一种方法是创建匿名护照策略:

// In anonymous.strategy.ts
@Injectable()
export class AnonymousStrategy extends PassportStrategy(Strategy, 'anonymous') {
  constructor() {
    super()
  }

  authenticate() {
    return this.success({})
  }
}

然后,在控制器中链接此策略:

// In create-post.controller.ts
@Controller()
export class CreatePostController {
  @UseGuards(AuthGuard(['jwt', 'anonymous'])) // first success wins
  @Post('/posts')
  async createPost(@Req() req: Request, @Body() dto: CreatePostDto) {
    const user = req.user as ExpressUser

    if (user.email) {
      // Do something if user is authenticated
    } else {
      // Do something if user is not authenticated
    }
    ...
  }
}
vdzxcuhz

vdzxcuhz3#

您可以添加一个公共装饰器

//decorator.ts
export const IS_PUBLIC_KEY = 'AllAnonymous';
export const AllAnonymous = () => SetMetadata(IS_PUBLIC_KEY, true);

然后在你的 JWT 卫士

//JWT authguard.ts
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  constructor(private reflector: Reflector) {
    super();
  }
  canActivate(context: ExecutionContext) {
    return super.canActivate(context);
  }

  handleRequest(err: any, user: any, info: any, context: ExecutionContext) {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);

    if (isPublic && !user) {
      return null;
    }

    if (err || !user) {
      throw err || new UnauthorizedException();
    }
    return user;
  }
}

现在可以在控制器中允许匿名访问,以便在用户经过身份验证时将用户包括在请求中

//controller.ts
  @AllAnonymous()
  @UseGuards(JwtAuthGuard)
  @Get('profile')
  getUserProfile(@Req() req: any) {
    {
      const { user } = req;

      console.log(user);

      return user
    }
  }

相关问题