当前位置: 首页 > 后端技术 > Node.js

如何使用Eggjs从零开始开发一个项目(三)

时间:2023-04-03 18:23:37 Node.js

上一篇我们写了用户注册登录的代码,学习了如何进行用户认证(JWT)以及如何安全地存储密码(hash)).在这篇文章中,我们有以下两个任务:获取token中的数据;通过模型来同步数据库。获取token中的数据当用户登录时,我们已经将用户的一些基本信息加密存储在token中。通过路由配置,我们可以很方便的控制哪些接口需要登录,哪些接口不需要登录。但是如果细化到用户或者用户角色,仅仅从路由层面是很难控制的。我们需要获取用户信息,并将用户信息存储在session中,以便我们随时访问。怎么做?这里我们需要写一个中间件来实现这个功能。代码如下://app/middleware/eggJwtmodule.exports=options=>{returnasyncfunctionjwt(ctx,next){consttoken=ctx.request.header.authorization;if(token){//这里有一个坑,前端一般会发送BearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoieGl...//但是解码不需要Bearer,需要手动处理consttokenStr=token.split('')[1];try{//解码令牌并将其存储在会话中间constdecode=ctx.app.jwt.verify(tokenStr,options.secret);ctx.session.user=解码;等待下一个();}赶上(错误){ctx.status=500;ctx.body={消息:error.message};返回;}}else{ctx.status=401;ctx.body={message:'用户未登录'};返回;}};};这里解释一下eggjs的插件机制,如果你在config.default.js中的Configuration:config.middleware=['eggJwt'];然后,这个插件会应用到所有的路由上,除非有特殊的配置,但是我们这里不需要,所以我们按需配置,不加这行代码://app/router.jsmodule.exports=app=>{const{路由器,控制器}=应用程序;constjwt=app.middleware.eggJwt(app.config.jwt);router.get('/',controller.home.index);router.post('/createUser',jwt,controller.user.createUser);router.get('/getUsers',jwt,controller.user.getUsers);router.post('/register',controller.user.register);router.post('/登录',controller.user.login);};我们可以根据需要手动导入和配置。这时,当我们访问配置了jwt的接口时,就会执行插件,解析token,并将解析结果保存到session中。让我们修改用户控制器的代码并尝试:asyncgetUsers(){//printsessionconsole.log(this.ctx.session.user,'===========');constusers=awaitthis.ctx.model.User.findAll();this.ctx.body={code:200,data:users};}配置token后,请求localhost:7001/getUsers,可以正常返回数据,控制台会打印Here:{name:'xiaoming',iat:1609055716,exp:1609062916}===========可以看到此时我们已经获取到了token中存储的数据。通过模型同步数据库按照我们现在的代码,如果需要调整模型中的字段,需要修改模型文件,然后再写一个脚本同步修改数据库中的字段,太麻烦了。幸运的是,Sequelize提供了一个方法,可以让我们根据模型来同步数据库中的字段:{force:true})-将创建表,如果该表已经存在,则先删除它User.sync({alter:true})-这将检查数据库中表的当前状态(它有哪些列,它们的数据类型等),然后在表中进行必要的更改以匹配模型。注意这里我们只能使用User.sync({alter:true}),那么什么时候执行呢?我们希望在每次服务启动时同步数据库字段,eggjs也提供了一个生命周期供我们使用://app.jsclassAppBootHook{constructor(app){this.app=app;}configWillLoad(){//这个时候已经读取并合并了config文件,但是还没有生效//这是应用层最后一次修改配置//注意:只有这个函数支持同步调用}asyncdidLoad(){//所有配置已经加载//可以用来加载应用自定义文件和启动自定义服务}asyncwillReady(){//所有插件都已经启动,但是应用作为一个整体还没有准备好//可以做一些数据初始化等操作,这些操作成功后才会启动应用//根据模型同步数据库awaitthis.app.model.sync({alter:真的});}asyncdidReady(){//应用程序已经启动}asyncserverDidReady(){//http/https服务器已经启动,开始接受外部请求//此时,可以从app中获取服务器实例。服务器}}module.exports=AppBootHook;这时候我们在用户模型中新增一个字段:nickname:STRING(10),然后重启一个下载服务,打开数据库,查看用户表。果然多了一个昵称栏。这个功能极大的方便了我们同步模型和数据库的字段,但是操作的时候一定要小心,不要误删字段。本文内容不多,但都是很实用的功能。下一篇我们将通过Sequelize实现表的关联查询。