ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

nest.js学习笔记(五) --jwt验证

2022-05-22 01:04:27  阅读:194  来源: 互联网

标签:const -- nest jwt auth user import nestjs


1、前期准备工作

a、安装数据库,mysql, 配置数据库连接参看四

b、新建User模块,用于管理User

实现注册:

@Controller('user')
export class UserController {
    public constructor(
        private readonly userService: UserService,
    ) {}

    @Post('/register')
    public async register(@Body() body: any) {
        return await this.userService.registerUser(body);
    }
}

userService实现简易版(注意,这里用的是bcrypt来实现对密码进行加密的,具体参看nest官方文档

@Injectable()
export class UserService {
    public constructor(@InjectRepository(User) private readonly user: Repository<User>) {}

    public async registerUser(info: { name: string; nickname: string; password: string }) {
        const { name, nickname, password } = info;

        const user = await this.user.findOne({ where: { name } });

        if (!user) {
            const saltOrRounds = 10;
            const pwd = await bcrypt.hash(password, saltOrRounds);
            await this.user
                .createQueryBuilder()
                .insert()
                .into(User)
                .values([
                    {
                        name,
                        nickName: nickname,
                        password: pwd,
                        createTime: Date.now() / 1000,
                        updateTime: Date.now() / 1000,
                    },
                ])
                .execute();

            return {
                code: 0,
                message: 'ok',
            };
        }

        return {
            code: 1,
            message: '用户已存在',
        };
    }
}

这样就已实现了简易版的注册

2、jwt的配置与验证

a、安装依赖

yarn add  @nestjs/passport passport passport-jwt  @nestjs/jwt -S
yarn add  @types/passport-jwt -D

b、创建 Auth 模块

nest g module /routers/auth    // 创建auth模块
nest g service /routers/auth    // 创建auth服务

c. 新建一个存储常量的文件

在 auth 文件夹下新增一个 constants.ts,用于存储各种用到的常量:

export const jwtSalt = '.even_jwt_@@__';

d、编写 JWT 策略

在 auth 文件夹下新增一个 jwt.strategy.ts,用于编写 JWT 的验证策略:

import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { jwtSalt } from './constants';
import * as crypto from 'crypto-js';

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

    // JWT验证 - Step 4: 被守卫调用
    async validate(payload: any) {
        console.log(`JWT验证 - Step 4: 被守卫调用`);
        const info = payload.info;

        // const userInfo = crypto.AES.decrypt(info, 'salt').toString(crypto.enc.Utf8);

        // console.log(JSON.parse(userInfo));
        return {
            info,
        };
    }
}

注意:为了防止jwt被编译出来,所以采用了加密方式, 注释掉的部份只是为了验证,可以不编写,如果有其他需求的话按该方式进行解码

e、编写auth.service.ts的验证逻辑

import { User } from '@app/entities/user.entity';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';
import * as crypto from 'crypto-js';

@Injectable()
export class AuthService {
    public constructor(
        @InjectRepository(User) private user: Repository<User>,
        private readonly jwtService: JwtService,
    ) {}

    // JWT验证 - Step 2: 校验用户信息
    public async validateUser(name: string, pwd: string): Promise<boolean> {
        const user = await this.user.findOne({
            select: ['name', 'password'],
            where: {
                name,
            },
        });

        return user && bcrypt.compare(pwd, user.password);
    }

    // JWT验证 - Step 3: 处理 jwt 签证
    public certificate(user: any): string {

        // 这里对jwt的内容采用了 crypto 中的aes的对称加密方法
        const payload = {
            info: crypto.AES.encrypt(
                JSON.stringify({ name: user.name, password: user.password }),
                'salt',
            ).toString(),
        };

        return this.jwtService.sign(payload);
    }
}

f、关联jwt策略与service到Auth.module模块中

import { JwtStrategy } from './jwt.strategy';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { User } from '@app/entities/user.entity';
import { jwtSalt } from './constants';

@Module({
    imports: [
        TypeOrmModule.forFeature([User]),
        PassportModule.register({ defaultStrategy: 'jwt' }),
        JwtModule.register({
            secret: jwtSalt,
            signOptions: { expiresIn: '30m' }, // token 过期时效
        }),
    ],
    providers: [AuthService, JwtStrategy],
    exports: [AuthService],  // 因为auth模块需要导入到User模块,所以需要配置导出
})
export class AuthModule {}

g、在user模块中需要导入AuthModule, 因为user模块需要用到签发证书以及用户验证的方法

import { TypeOrmModule } from '@nestjs/typeorm';
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { User } from '@app/entities/user.entity';
import { AuthModule } from '../auth/auth.module';

@Module({
    imports: [TypeOrmModule.forFeature([User]), AuthModule],
    providers: [UserService],
    controllers: [UserController],
    exports: [UserService],
})
export class UserModule {}

h、在UserController中添加登录的方法

import { AuthService } from './../auth/auth.service';
import { UserService } from './user.service';
import { Body, Controller, Post } from '@nestjs/common';

@Controller('user')
export class UserController {
    public constructor(
        private readonly userService: UserService,
        private readonly authService: AuthService,
    ) {}

    @Post('/register')
    public async register(@Body() body: any) {
        return await this.userService.registerUser(body);
    }

    @Post('/login')
    public async login(@Body() body: any) {
        const { name, nickname, password } = body;

        const result = await this.authService.validateUser(name, password);

        if (result) {
            return {
                code: 0,
                message: 'ok',
                token: this.authService.certificate({ name, password }),  // 签发token
            };
        }

        return {
            code: 1,
            message: 'fail',
        };
    }
}

i、在指定路径上添加jwt验证

@UseGuards(AuthGuard('jwt')) // 使用 'JWT' 进行验证
@Get()
public async init() {
    const result = await this.cryptoService.cryptoPassword();
    return {
        code: 0,
        token: result,
    };
}

这个时候访问已需要验证的路由,那么就需要在header中添加 字段  Authorization

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbmZvIjoiVTJGc2RHVmtYMStpVW1NMXBzWm13b3YyUS9QSHBTY3lqMzBTOVFpb1pDZW
xPdHRvSGo2Rm9wZFZXSnFoNko4M3hPb2NsK1QzanNIS0NuaXNRUkVnckE9PSIsImlhdCI6MTY1MzE0OTYwMiwiZXhwIjoxNjUzMTUxNDAyfQ.vp62XIxwdynol4aql7
XgYE4-Xpq1PcpaTUzLbd5UHyU
这里也说一下 JWT 的缺点,主要是无法在使用同一账号登录的情况下,后登录的,挤掉先登录的,也就是让先前的 Token 失效,从而保证信息安全, 这里就需要配合redis来实现唯一性登录

 

标签:const,--,nest,jwt,auth,user,import,nestjs
来源: https://www.cnblogs.com/venblogs/p/16296722.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有