Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

我们都知道,http协议本身是无状态的协议,如果在一个系统中,我们只有登录后在可以操作,由于http是无状态的,所以那就必须每个接口都需要一个认证,来查看当前用户是否有权限。今天我们就基于之前的项目,集成JWT。

1 user.service方法
增加一个查询单个用户的方法,这个方法不需要对应控制器。

async findOne(name: string): Promise<any | undefined> {  const user = await this.UserRepository.findOne({    where: {      name: name,    },  });  if (user == undefined) {    return void 0;  } else {    return user;  }}

2 增加登录路由
在user.controller文件中新增路由,里面的逻辑暂时什么都不写

 @Post('/login')  async login(@Body() loginParmas: any) {}

3 安装依赖

 yarn add passport passport-jwt passport-local @nestjs/passport @nestjs/jwt -S

4 创建Auth模块
src下新建文件夹logical/auth,auth目录下为我们逻辑功能。
constants.ts - 常量

export const jwtConstants = {  secret: 'NestAPI',};

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,    });  }  // JWT验证 - Step 4: 被守卫调用  async validate(payload: any) {    return {      id: payload.id,      name: payload.name,      nickname: payload.nickname,    };  }}

auth.service.ts - 验证逻辑

import { Injectable, Inject } from '@nestjs/common';import { JwtService } from '@nestjs/jwt';import { UserService } from '../../user/user.service';import { encryptPassword } from '../../utils/cryptogram';@Injectable()export class AuthService {  constructor(    @Inject('UserService') private readonly usersService: UserService,    private readonly jwtService: JwtService,  ) {}  // JWT验证 - Step 2: 校验用户信息  async validateUser(name: string, password: string): Promise<any> {    const user = await this.usersService.findOne(name);    if (user) {      const hashedPassword = user.password;      const salt = user.passwdSalt;      // 通过密码盐,加密传参,再与数据库里的比较,判断是否相等      const hashPassword = encryptPassword(password, salt);      if (hashedPassword === hashPassword) {        // 密码正确        return {          code: 1,          user,        };      } else {        // 密码错误        return {          code: 2,          user: null,        };      }    }    // 查无此人    return {      code: 3,      user: null,    };  }  // JWT验证 - Step 3: 处理 jwt 签证  async certificate(user: any) {    const payload = {      id: user.id,      name: user.name,      nickname: user.nickname,    };    try {      const token = this.jwtService.sign(payload);      return {        code: 200,        data: {          token,        },        msg: `登录成功`,      };    } catch (error) {      return {        code: 600,        msg: `账号或密码错误`,      };    }  }}

auth.module.ts

import { Module } from '@nestjs/common';import { AuthService } from './auth.service';import { JwtStrategy } from './jwt.strategy';import { UserModule } from '../../user/user.module';import { PassportModule } from '@nestjs/passport';import { JwtModule } from '@nestjs/jwt';import { jwtConstants } from './constants';@Module({  imports: [    PassportModule.register({ defaultStrategy: 'jwt' }),    JwtModule.register({      secret: jwtConstants.secret,      signOptions: { expiresIn: '8h' }, // token 过期时效    }),    UserModule,  ],  providers: [AuthService, JwtStrategy],  exports: [AuthService],})export class AuthModule {}

上面这些属于配置,调用我们需要在路由/login里面写逻辑,第2步中我们只定义了一个空的方法,我们接下来写逻辑

import { ApiTags, ApiParam, ApiQuery, ApiHeader } from '@nestjs/swagger';import {  Controller,  Post,  Body,  Logger,  HttpCode,  UseGuards,} from '@nestjs/common';import { AuthGuard } from '@nestjs/passport';import { AuthService } from '../logical/auth/auth.service';import { UserService } from './user.service';@ApiTags('用户管理')@Controller('user')export class UserController {  constructor(    private readonly authService: AuthService,    private readonly userService: UserService,  ) {}  /**   * 用户登录   */  @Post('/login')  async login(@Body() loginParmas: any) {    const authResult = await this.authService.validateUser(      loginParmas.name,      loginParmas.password,    );    switch (authResult.code) {      case 1:        return this.authService.certificate(authResult.user);      case 2:        return {          code: 600,          msg: `账号或密码不正确`,        };      default:        return {          code: 600,          msg: `当前用户未查到`,        };    }  }}

5 测试
运行项目,我们用postman测试

©著作权归作者所有:来自51CTO博客作者mb5fd86dae5fbf6的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 【Nest教程】数据验证class-validator
  2. 不要把异常当做业务逻辑,这性能可能你无法承受
  3. 漫画:聊一聊MVC、MVP、MVVM?
  4. Traefik 2 基础授权验证(前篇)
  5. Traefik 2 基础授权验证(后篇)
  6. 用sa-token轻松解决网站权限验证
  7. 使用Shiro加密与解密实现简单用户注册与登录验证
  8. RxJava(十)switchIfEmpty 操作符实现 Android(安卓)检查本地缓存逻
  9. Android(安卓)锁屏和黑屏的广播消息

随机推荐

  1. 前后端都分离了,该搞个好用的API管理系统
  2. 芋道 Spring Boot 消息队列 RocketMQ 入
  3. 9款最佳编程字体推荐
  4. Apollo 源码解析 —— Portal 创建 Clust
  5. 快30岁的我,终于赚到人生第一个10W!
  6. HTML5 超炫酷 3D 烟花动画
  7. 芋道 Spring Boot API 接口文档 Swagger
  8. Android(安卓)Studio 使用Gradle编译 如
  9. 纯CSS3实现大象走路动画
  10. BI发展趋势全景