【nest】nest学习笔记(七)

14 篇文章 3 订阅

前言

  • 本篇主要是jwt使用和passport相关

官网

流程

  • nest 新开个项目 nest new xxx
  • 按照指示,安装:
$ npm install --save @nestjs/passport passport passport-local
$ npm install --save-dev @types/passport-local
  • 生成auth模块和users模块
$ nest g module auth
$ nest g service auth
$ nest g module users
$ nest g service users
  • 修改user的服务:
import { Injectable } from '@nestjs/common';

export type User = any;

@Injectable()
export class UsersService {
  private readonly users: User[];

  constructor() {
    this.users = [
      {
        userId: 1,
        username: 'john',
        password: 'changeme',
      },
      {
        userId: 2,
        username: 'chris',
        password: 'secret',
      },
      {
        userId: 3,
        username: 'maria',
        password: 'guess',
      },
    ];
  }

  async findOne(username: string): Promise<User | undefined> {
    return this.users.find(user => user.username === username);
  }
}
  • modules中将服务暴露
 exports: [UsersService],
  • auth 服务中制作验证user的方法:
import { Injectable } from '@nestjs/common';
import { UsersService } from '../users/users.service';

@Injectable()
export class AuthService {
  constructor(private usersService: UsersService) {}

  async validateUser(username: string, pass: string): Promise<any> {
    const user = await this.usersService.findOne(username);
    if (user && user.password === pass) {
      const { password, ...result } = user;
      return result;
    }
    return null;
  }
}
  • 同时auth的模块中导入user的模块
  • 新建local.strategy.ts:
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}
  • 使用别的字段在super里改super({ usernameField: ‘email’ })
  • 然后在模块中导入passportModule,提供上面建立的服务:
@Module({
  imports: [UsersModule,PassportModule],
  providers: [AuthService,LocalStrategy],
})
  • 在appcontroller里面用守卫做个Post路由:
import { Controller, Request, Post, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Controller()
export class AppController {
  @UseGuards(AuthGuard('local'))
  @Post('auth/login')
  async login(@Request() req) {
    return req.user;
  }
}
  • 此时启动nest ,已经可以post了,输入:
	{
		"username": "john",
		"password": "changeme"
	}
  • 则可以正确返回user ,否则直接跳401。
  • 还可以进行转换下,新建local-auth.guard.ts:
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}
  • 守卫处改为:
 @UseGuards(LocalAuthGuard)

结合jwt

  • 需要安装:
$ npm install --save @nestjs/jwt passport-jwt
$ npm install --save-dev @types/passport-jwt
  • 首先在auth服务里声明jwtService并增加登录方法:
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { UsersService } from '../users/users.service';

@Injectable()
export class AuthService {
  constructor(
    private usersService: UsersService,
    private jwtService: JwtService,
  ) {}

  async validateUser(username: string, pass: string): Promise<any> {
    const user = await this.usersService.findOne(username);
    if (user && user.password === pass) {
      const { password, ...result } = user;
      return result;
    }
    return null;
  }
  async login(user: any) {
    const payload = { username: user.username, sub: user.userId };
    return {
      access_token: this.jwtService.sign(payload),
    };
  }
}
  • 需要设立个盐值:
export const jwtConstants = {
  secret: 'secretKey',
};
  • auth模块中导入注册:
 JwtModule.register({
      secret: jwtConstants.secret,
      signOptions: { expiresIn: '60s' },
    }),
  • jwt更多配置
  • 修改控制器路由,当验证通过后,走jwt服务,传递user过去,jwt服务对user进行加密,返回accesstoken。
  • 如果import 了authmodule,就别在provider里去引入服务,否则会让你再注册遍。
  • controller里直接调用服务:
  @UseGuards(LocalAuthGuard)
  @Post('auth/login')
  async login(@Request() req) {
    return this.authService.login(req.user);
  }
  • 这样输入正确后则返回accesstoken。
  • 下面制作Jwt passport
  • 新建jwt.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { jwtConstants } from './constants';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: jwtConstants.secret,
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}
  • jwtFromRequest 一般都是提取bearerToken,这个是约定。
  • 第二个忽略过期,就是过期就无效。
  • provider中导入它:
 providers: [AuthService, LocalStrategy, JwtStrategy],
  • 新建jwt-auth.guard.ts:
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
  • 控制器老方法加一下:
  @UseGuards(JwtAuthGuard)
  @Get('profile')
  getProfile(@Request() req) {
    return req.user;
  }
  • 此时就完成了。
  • 可以试下,先拿到accesstoken 然后设置请求头Authorization 值为Bearer token返回符合预期即可成功。
  • 有可能不满足现有jwt的验证,需要额外逻辑,可以这么写:
import {
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  canActivate(context: ExecutionContext) {
    // Add your custom authentication logic here
    // for example, call super.logIn(request) to establish a session.
    return super.canActivate(context);
  }

  handleRequest(err, user, info) {
    // You can throw an exception based on either "info" or "err" arguments
    if (err || !user) {
      throw err || new UnauthorizedException();
    }
    return user;
  }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

业火之理

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值