nest.js + typeORM:身份认证,事务管理

Posted Novak

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nest.js + typeORM:身份认证,事务管理相关的知识,希望对你有一定的参考价值。

知识点

  • jwt身份认证
  • md5加密
  • typeorm事务(transaction)的使用

本文会延续上一篇文章,继续实现login功能,并实现API的身份认证,查看全部源码

JWT身份认证

对与绝大多数应用程序来说,身份认证是必不可少的组成部分,而对用户的身份认证授权的策略和方法非常多,选用何种方法取决于项目的需求。

passport是node.js中的一个比较流行的认证库,本项目Demo会使用passport-jwt策略来实现用户身份认证。

JWT(Json Web Token)是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

安装

npm install --save @nestjs/passport passport passport-jwt  jsonwebtoken

添加jwt.stratagy.ts:

import { ExtractJwt, Strategy } from \'passport-jwt\';
import { AuthService } from \'./auth.service\';
import { PassportStrategy } from \'@nestjs/passport\';
import { Injectable, UnauthorizedException } from \'@nestjs/common\';
import { JwtPayload } from \'./jwt-payload.interface\'

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

  async validate(payload: JwtPayload, done: Function) {
    console.log(\'entered jwt\')
    const user = await this.authService.validateUser(payload.userNmae);
    if (!user) {
      return done(new UnauthorizedException(), false);
    }
    done(null, user);
  }
}

通过validate()方法获取token然后传递给auth.service进行验证。

添加autn.service.ts:

import { Injectable } from \'@nestjs/common\'
import { Repository } from \'typeorm\';
import { JwtPayload } from \'./jwt-payload.interface\'
import * as jwt from \'jsonwebtoken\';
import { Employee } from \'../entities/employee.entity\'
import { InjectRepository } from \'@nestjs/typeorm\';

@Injectable()
export class AuthService {
    user: Employee
    constructor(
        @InjectRepository(Employee)
        private readonly employeeRepository: Repository<Employee>) { }

    async createToken(userName: string, passwoerd: string): Promise<any> {
        const user: JwtPayload = { userNmae: userName, passwoerd: passwoerd }
        return jwt.sign(user, \'secretKey\', { expiresIn: 3600 });
    }

    async validateUser(name: string): Promise<any> {
        return this.employeeRepository.findOne({ name: name });
    }

    async findEmployeeByName(name: string): Promise<Employee> {
        return this.employeeRepository.findOne({ name: name });
    }

    getUser(): Employee {
        return this.user;
    }

    async login(name: string, password: string): Promise<any> {
        this.user = await this.employeeRepository.findOne({ name: name });
        if (this.user != undefined && this.user.password == password) {
            return this.createToken(this.user.name, this.user.password);
        } else {
            return \'login failed !\'
        }
    }
}

在auth.service中,createToken()用来生成Token信息,validateUser()验证身份信息,login用于用户登录,在login中先根据用户名查询用户验证密码,然后生成Token返回给前端。这里在生成token是指定了到期时间和secretkey.

auth.controller.ts:

import { Controller, Get, Param, UseGuards, HttpStatus, HttpCode } from \'@nestjs/common\';
import { AuthService } from \'./auth.service\';
import { AuthGuard } from \'@nestjs/passport\';
import { callback } from \'./jwt.strategy\'

@Controller(\'auth\')
export class AuthController {
    constructor(private readonly authService: AuthService) { }
    @Get(\'login\')
    @HttpCode(HttpStatus.OK)
    async login(@Param() params): Promise<any> {
        return this.authService.login(params.name, params.password);
    }

    @Get(\'checklogin\')
    @UseGuards(AuthGuard(\'jwt\', { session: false, callback }))
    //@UseGuards(new RoleGuard([\'admin\']))
    public checkLogin() {
        return "valid user:" + this.authService.getUser().name;
    }
}

auth.controller中checklogin在访问时,使用passport的UserGuard配置jwt策略来验证身份信息,并在验证完成后指定调用callback函数。

MD5加密

本Demo使用了一个比较简单的加密策略,MD5。

安装包:

npm install --save @types/crypto-js crypto-js

加密过程也比较简单

import * as crypto from \'crypto-js\'

employee.password = crypto.MD5(\'123\').toString();

typeorm 事务的使用(transaction)

事务在srvice中是比较常见的应用场景,在typeorm的官方文档中提供了多种方法来进行事务管理,本文介绍两种基本的使用方法。

1.getManager(隐式commit,隐式rollback)

async edit(): Promise<string> {if (employee) {
            return getManager().transaction(async transactionalEntityManager => {
                await transactionalEntityManager.update<Employee>(Employee, { name: \'novak\' }, { age: 23 });
                await transactionalEntityManager.delete<Company>(Company, { id: 10 });
                let a = \'123bew\';
                console.log(a[10].length);//制造异常
            }).then(res => {
                return \'tranction done\'
            }).catch(Error => {
                return \'tranction failed, \' + Error;
            })
        } else {
            return \'employee not found\';
        }
    }

使用getManager().transaction来创建事务模块,为了验证效果,本文特意写了一个异常语句。验证结果是:出现异常后事务会自动回滚;如果没有异常,事务自动提交。

2.queryRunner(显式commit,显式rollback)

async editUseQueryRunner(): Promise<string> {
        let employee = await this.employeeRepository.findOne({ name: "novak" });
        console.log(employee)
        if (employee) {
            const connection = getConnection();
            const queryRunner = connection.createQueryRunner();
            await queryRunner.connect();

            await queryRunner.startTransaction();
            try {
                await queryRunner.manager.update<Employee>(Employee, { name: \'novak\' }, { age: 24 });
                /* let a = \'123bew\';
                console.log(a[10].length); */
                await queryRunner.commitTransaction();
                return \'transaction done\'
            } catch (err) {
                await queryRunner.rollbackTransaction();
                return \'transaction failed\'
            }
        } else {
            return \'employee not found\'
        }
    }

从代码中就可以看到queryRunner是显式的提交和回滚事务的。

 

以上是关于nest.js + typeORM:身份认证,事务管理的主要内容,如果未能解决你的问题,请参考以下文章

无法连接到数据库 - NEST.JS 和 TypeORM

如何在 typeorm 和 nest.js 中设置布尔验证

Nest.js + TypeORM + OpenApi 中虚拟(计算)列的最佳实践

Nest js 和 typeorm 自定义存储库问题

Nest.js TypeORM 连接到本地数据库(在 docker 容器上)

在 Nest JS / TypeORM 中使用具有关系的实体内部的实体并填充数据库