zoukankan      html  css  js  c++  java
  • 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是显式的提交和回滚事务的。

  • 相关阅读:
    shell编程:for循环结构
    shell编程:实现shell字符串连接功能
    jq 出现 $.cookie is not a function
    jq页面换肤效果
    js ==与===区别(两个等号与三个等号)
    JS与Jquery的事件委托机制
    jq选项卡切换功能
    licecap图片区域问题
    jquery网页定位导航特效
    ps-手捧城堡滴水云雾图
  • 原文地址:https://www.cnblogs.com/novak12/p/9270950.html
Copyright © 2011-2022 走看看