问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

nestjs项目实战:基于nuxt的用户管理系统开发

创作时间:
作者:
@小白创作中心

nestjs项目实战:基于nuxt的用户管理系统开发

引用
CSDN
1.
https://blog.csdn.net/weixin_55458088/article/details/137874816

本文将介绍如何使用nestjs和nuxt构建一个简单的用户管理系统。系统包括用户注册、登录、权限控制等功能,并使用JWT进行身份验证,使用bcrypt进行密码加密存储。

之前本来是想把学习用的nest测试项目部署上去实现增删改查已经联表查询功能试试的,但是想想既然已经部署到服务端并且能正常运行了,那本地跟服务端差别不大了,还不如搞个真正的需求部署上去,所以今天想自己用nuxt3+vue3+vant4+nestjs+mysql实现一个简单的人员管理系统

首先第一步:阿里云服务器实例转配
之前选了按量付费,一天要五块多,太心疼了,转包月先
正式开始:

1、新建nest项目

在我们想要新建nest项目的目录下打开命令行工具运行以下命令

nest new project-name  

为了让我们的请求地址看起来正规一点,我们这里加上一个统一的前缀吧
main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.setGlobalPrefix('manager')
  await app.listen(3000);
}  

2、新建user模块

src目录下运行以下命令

 nest g res user  

出现选项选第一个跟Y就行了,它们自动把你新建的模块引入到app主模块中去
src目录下已经有user模块并且在app.module中自动引入了

3、启动nestjs项目

要加dev,才有热更新

npm run start:dev  

报了个错:
因为这个端口之前有个工程正在用着,那我们先把这个工程关掉吧,暂时用不着,重新启动,出现以下这些表示成功了
访问一下:localhost:3000
找不到地址,因为我们之前设置了全局的前缀manager,加上
成功
我们先来构建一个用户的实体吧,一个用户拥有哪些基本数据:
用户名,不能重复,昵称(可选),密码,创建时间,最后一次登录时间,角色(用于控制权限,后面需要新建权限表),id(自增),用户状态(枚举值),deleted(用于软删除,新建时默认为否),token数组,因为考虑到多端登录情况,暂时想到这些,后面可以再加,其实还想搞个头像功能的,但是考虑到还要专门搞个文件服务器,还是先不搞了
过程:
1、新建user,token实体

2、在app.module中引入TypeOrmModule连接数据库

3、在user.module中引入TypeOrmModule并放入user,token实体

4、在user.service中引入两张库表,用来对对应表进行增删改查操作

都保存完之后数据库中已经出现这两张表了

新增用户接口写好之后调一下接口(中间具体过程不细讲,看完nestjs教程基本上就知道怎么搞了)
成功了,再看下数据库中数据,有了

为了后面删除操作,我们多搞了几条测试数据
自己把增删改查搞定了,中间过程省略,这里默认你们是会nest的,后续等我熟悉了nest可以考虑再仔细讲讲,现在自己也是个初学者状态

4、新建nuxt3前端工程

npx nuxi@latest init <project-name>  

后面很多活都可以交给tongyilingma了,比如你直接跟他说,我要用某某组件(例:element-plus,甚至可以带上具体版本号)写一个后台管理页面,或者写一个表格,表格里面有哪些内容,写一个弹窗,弹窗里面有哪些内容,然后copy到页面里面,改写数据,就差不多了,看下效果
增删改查都写好了,增删改查的弹窗都可以交给tongyilingma然后自己稍微改改调接口就行
经测试增删改查功能都没问题,接着我们既然要模拟真实应用,就要对后端应用进行改良

5、登录

登录方法给用户发token,数组存储,但是我们这里暂时只允许存在一个token
jwt依赖自己安装:

npm i jsonwebtoken
const jwt = require('jsonwebtoken');  

调用login方法,搞定
token校验,校验通过返回用户信息即可:

async checkToken(token: string) {
    try {
      const decoded = jwt.verify(token, secretKey);
      console.log('checktoken decoded ', decoded.userId)
      if (decoded.userId) { // 验证通过,返回用户信息
        const user = await this.usersRespository.findOne({
          where:
            { id: decoded.userId }
        });
        console.log('checktoken user ', user)
        return user
      }
      return decoded;
    } catch (err) {
      console.log('checkToken err ', err)
      return null;
    }
  }  

6、密码加解密

  1. 前后端传输加密,这里用我们常用的aes(对称加解密),这一步搞了好久,篇幅较长,重起一片文章写这个了:前端cryptojs加解密,后端node环境(nestjs)crypto加解密
  2. 数据库存储密码加密,我们肯定不能直接前端加密密码传输然后后端直接将前端aes加密后的密码字段存在数据库,因为我们知道对称加密前后端秘钥一致,且这个秘钥是很容易搞到的,所以如果直接存前端传过来的加密密码方案肯定不可行,而且一般前后端加密传输一般都是针对整个请求对象加解密,一般不止针对密码加密
  • 所以这里我们用nestjs推荐的bcypt
npm i bcrypt
npm i -D @types/bcrypt  
  • 存储密码前加密

user.password = await bcrypt.hash(user.password, config.pwdSaltOrRounds)  

调用添加方法,再查看数据库:

可以看到,数据已经被加密了
这时候我们能想到,之前登录方法里面的用户名密码对比肯定走不通了,bcrypt提供了对比方法,因为我们给user的实体中的password设置了select:false,是无法查询到的,所以这里要加select才能查出来
调用一下登录方法,成功
注意要在我们搞完加解密之后调接口新产生的数据,才是有做数据库存储加解密的数据
让我们输个错误密码试下,没问题
在这里说一下,不要用前端传入密码用bcrypt加密然后跟数据库存储的密码去做对比,因为每次机密产生的字符串都是不一样的,结果永远是false,要用bcrypt提供的同步对比方法

bcrypt.compareSync(password, res[0].password)  

7、权限控制

这是最后一步,作为管理系统,用户的增删改查肯定不是所有用户都有权限操作,所以我们要加一个权限控制,所以我们要在加一个用户角色表
每个用户暂时只能有一个角色吧,一对一
每个路由前面加个权限判断

if (headers.token) {
      const hasPermission = await this.userService.hasPermission(PermissionCode.ADD, headers.token)
      if (hasPermission) {
        return await this.userService.create(createUserDto);
      } else {
        return { message: '没有添加用户权限' };
      }
    } else {
      return {
        message: '没有添加用户权限'
      }
    }  

权限判断

async hasPermission(permission: PermissionCode, token: string): Promise<boolean> {
    if (!permission || !token) {
      return false
    }
    const adminPermissions = [PermissionCode.ADD, PermissionCode.DELETE, PermissionCode.UPDATE, PermissionCode.QUERY]
    const operatorPermissions = [PermissionCode.ADD, PermissionCode.QUERY]
    const userPermissions = [PermissionCode.QUERY]
    const user = await this.checkToken(token)
    console.log('hasPermission user ', user)
    if (user && user.roles && user.roles.code) {
      if (user.roles.code === RoleCode.ADMIN && adminPermissions.includes(permission)) {
        return true
      }
      if (user.roles.code === RoleCode.Operator && operatorPermissions.includes(permission)) {
        return true
      }
      if (user.roles.code === RoleCode.USER && userPermissions.includes(permission)) {
        return true
      }
    }
    return false
  }  

首先,未登录状态下试下
没问题,让我们登录管理员再试下,添加成功
这里面用到的登录就是常规的,登录完之后得到token,把token放在缓存里面,在请求的时候把token放在请求头里面,服务端拿这个token去做校验,校验通过拿到用户信息及用户角色信息,根据角色信息判断是否有改权限,从而继续后面的操作
到这里一个简单的用户管理系统就基本完成了,看到这里的是默认会nest的,所以中间很多nest的基础部分就没有细讲了

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号