D8 的训练是在应用里添加一个用户模块,定义一个用户实体,这会在应用的数据库里对应一个数据表,来存储用户相关的数据。
Nest.js 应用可以使用模块来组织应用的结构,一般你需要一种新的实体,就可以围绕这种实体去创建一个模块。我们的应用需要处理用户资源,所以要创建一个用户实体,围绕用户实体可以再去创建一个用户模块。
下面是定义的 User 模块:
import { Module } from '@nestjs/common'; import { UserController } from './user.controller'; import { UserService } from './user.service'; import { User } from './user.entity'; @Module({ controllers: [UserController], providers: [UserService] }) export class UserModule { }
定义模块用的这个类的上面要用 @Module 装饰,给它一个配置对象,在这个对象里描述一个模块里包含的一些东西,比如控制器、服务等等。
Hash 用户密码
在用户模块里你可以添加创建新用户用的接口,用户可以通过客户端把要注册的用户信息发送到这个用户注册接口上,接口收到了注册请求,可以去检查要申请的用户名是否已经存在,如果存在就响应回一个异常信息,告诉客户端用户名已经存在了。
如果要注册的用户不存在,就可以存储用户数据,不过这个数据里的密码要特别处理一下,用户的密码需要 Hash 一下。也就在我们应用的数据库存不能存储用户真实的密码,而是存储的 Hash 之后的密码,Hash 之后的密码谁也不知道真实的密码是什么,比对密码是否匹配的时候要使用一种特别的方法去比较。存储 Hash 之后的密码,这样做更安全一些。
Hash 密码、比对密码与 Hash 密码,可以使用 Bcrypt 这个 Package 提供的功能。注意在安装这个包的时候需要编译,会要求系统上有特定的环境才行,比如要有 Python,所以安装它的时候如果环境不对,很可能会遇到问题。如果你发现不能正常安装 Bcrypt,可以使用 Bcrypt.js 这个包代码它,这个包是用纯 JavaScript 代码写的,不需要编译模块,缺点是性能不如 Bcrypt 。
实体监听器
在什么时候执行 Hash 密码?当然你可以直接在注册接口的处理器或处理器用的服务方法里面,提取客户端发送的数据里的密码,然后 Hash 一下,再把它存储在数据库里。更好一点的方法是使用 TypeORM 上的实体监听器,它们会监听发生在实体上的一些特定的事件,发生这些事情的时候可以去执行一些动作。
比如我们可以监听一下用户实体的新建或更新事件,发生这些事情的时候都可以去 Hash 一下用户的密码。
@BeforeInsert() @BeforeUpdate() async hashPassword() { this.password = await bcrypt.hash(this.password, 12); }