「fastify项目实战」投票Web应用之四

「fastify项目实战」投票Web应用之三
「fastify项目实战」投票Web应用之二
「fastify项目实战」投票Web应用之一

Fastify框架的的封装模型是整个框架的核心,前三篇文章中我们首先采用最基础的路由功能实现了一个投票应用功能,通过这个功能来看,它与其它的Web开发框架相比,其简易程度与Express差不多,之后,我们逐步地引入了fastify框架中的插件概念,将之前的路由组件全部采用插件实现。采用插件进行Web开发才是fastify主打的特点。

在第三篇文章《投票Web应用之三》中,我们将用户数据users和投票数据votes分别放置在对应的路由插件中,数据和路由其实是两个弱相关的内容,路由插件在执行相应的请求时会使用对应的数据并将其返回给用户,我们可以将路由与数据进行解耦,路由只负责路由相关的功能,数据则抽象为对应的数据模型。本项目将之前的路由插件拆分为两个插件:路由插件和数据模型插件。数据模型插件的存放位置与路由的存放位置属于同一级别,在routes的同一级目录,创建一个名称为models的目录,我们将所有的数据模型插件存放在这个目录下。

用户数据模型主要是管理用户的信息,实现对用户数据的逻辑操作,比如:用户的创建、用户的查询等,用户数据模型不直接与Web请求进行交互,它只负责对路由器提供数据支持。在models目录下新建一个users.mjs文件,按照fastify插件要求,实现一个插件函数,并将其导出为缺省函数。如下图1所示

「fastify项目实战」投票Web应用之四

图1

之后,我们将路由插件中的users数据删除,在用户模型插件中加入这些数据,这些数据位于user.mjs文件的最开始的地方,如下图2所示。

「fastify项目实战」投票Web应用之四

图2

接下来,我们将所有与用户相关的操作编写在user.mjs用户插件中。定义一个用户模型对象userModel,它用于管理在这个应用中的用户数据,这个用户对象的功能主要有下面的几项功能:

  1. 用户列表
  2. 创建用户
  3. 查找用户
  4. 删除用户
  5. Token处理

我们将以上5个功能全部实现为用户模型的方法,这些方法实现后,用户路由器只需要向用户模型调用对应的方法就可以了,无需再将这些代码在用户路由器中实现,明确了二者之间的职责。

用户列表

用户列表的存储还是以数组的方式存放在users数组中,所不同的是:用户模型提供了一个成员属性data,它表示用户列表成员,在用户模型的其它方法中,我们同样使用data成员来进行访问这些数据。访问用户列表时,如果没有任何限制条件,那么它将返回所有的用户数据,但是在返回用户数据时,数据模型对其进行了安全限制,它将敏感信息hashedPassword属性剔除了,如下图3所示,只保留了3个属性。

「fastify项目实战」投票Web应用之四

图3

创建用户

创建用户是指客户端提供用户的邮件地址、昵称和密码等信息,服务器经过校验后交给用户模型进行存储,在数据模型这一层,它将不再进行任何的数据验证。但是,有两个属性需要在存储数据之前进行生成:一个数据是这个用户的唯一Id值,另一个是用户的密码哈希值,这两个值生成后,便可以将用户的信息存入到用户列表中。如图4所示

「fastify项目实战」投票Web应用之四

图4

用户的Id值如何生成呢?还是按照之前生成Id的方法,使用最后一个用户的Id值,再对其加1即可,这个功能被封装成为了一个函数nextId,其定义如下图5所示:

「fastify项目实战」投票Web应用之四

图5

图5中第39行代码首先判断当前用户列表的长度是否为0,如果是的话,表示当前没有用户存在,那么新生成的用户Id值为1;如果已经存在了其它用户,则取出用户列表中的最后一个Id值并对其加1,第40行代码实现了此功能。

为什么要做密码的哈希值存储呢?主要是为了安全!当然本代码实现并不安全,它既没有“撒盐”处理,也没有采用标准的哈希算法,它只是将原密码之后加了一个字符“0”,仅仅是为了表明:在存储用户密码时,我们是需要对其进行处理后才可以存储,而不是以明文的方式直接保存至数据库中。我们的哈希函数定义如下图6所示:

「fastify项目实战」投票Web应用之四

图6

查找用户

通常情况下,我们并不需要获取所有的用户列表,而只是一个或几个用户的信息,这样我们就可以提供一个或几个用户的Id值,将这些Id值作为查询用户的条件,只有满足这些条件的用户信息才会返回给客户端,如下图7所示。

「fastify项目实战」投票Web应用之四

图7

图7中,第52行代码使用filter方法对数组中的用户数据进行了过滤,只有包含在ids数组中的用户才会被返回,最后通过第53-57行代码将敏感属性hashedPassword过滤掉。这样我们就获取到了id值位于ids数组中的所有用户信息了。

删除用户

删除用户操作是指根据用户指定的Id值,将用户信息从数组中删除掉。它首先需要检查此用户是否存在,如果不存在的话,就不需要执行任何操作,直接返回一个0值,反之,则执行删除操作后,返回1值,如图8所示

「fastify项目实战」投票Web应用之四

图8

Token处理

Token是服务器端生成,并返还给客户端的一个数字串,其内容由服务端定义和解释,客户端无需关心它所携带的内容含义,只需要在发送请求时将其原样的传递给服务器就可以了。与hashedPassword一样,它也是安全相关的一个内容,服务器需要对其进行相关的加密处理,当服务器接收到客户端含有token的请求时,需要对其进行解密处理,提取出自己感兴趣的内容。本例中演示token功能包含生成token和校验token。

「fastify项目实战」投票Web应用之四

图9

图9为生成token的代码,它使用了用户的Id值作为token的一部分内容,以冒号为分隔符“:”构建一个token字符串,冒号分割的两边内容是对称的。

「fastify项目实战」投票Web应用之四

图10

校验token是否合法采用了冒号两边字符串的对称性,如果两边的内容符合对称性条件,那么就认为是一个合法的token,否则,视为非法token。

构建用户模型插件

以上内容我们完成了用户模型的构建,最后是将这个模型转换为对应的插件,这个插件就负责提供用户操作相关的功能。下图11为用户模型的插件代码

「fastify项目实战」投票Web应用之四

图11

图11第87行代码调用了fastify的decorate方法,称为装饰器方法。它是fastify提供的扩展其核心对象的一种方式,你可以使用它扩展fastify实例、请求对象或者是响应对象等,扩展的内容包括对象、方法等。本例中图11对fastify实例扩展了一个userModel属性,这个属性的类型为一个用户模型对象。

完成用户模型插件的创建之后,接下来就是如何使用它了,我们将在下一篇文章中演示如何使用这个插件来简化用户路由插件代码,二者之间又是如何进行通讯的。谢谢阅读,我们下一篇文章见!

「fastify项目实战」投票Web应用之三-今日头条 (toutiao.com)
「fastify项目实战」投票Web应用之二-今日头条 (toutiao.com)
「fastify项目实战」投票Web应用之一-今日头条 (toutiao.com)

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章