上一篇中咱們編寫了用戶註冊登陸、登陸的代碼,學習瞭如何進行用戶的認證(JWT),如何安全地存儲用的密碼(hash)。這一篇咱們有如下2個任務:javascript
token
中的數據;model
來同步數據庫。用戶登陸的時候咱們已經用戶的一些基本信息加密存儲到token
中,經過路由配置咱們能簡單的去控制哪些接口須要登陸,哪些接口不須要登陸,可是若是再細化到用戶或者用戶角色,只是從路由層面就難以控制了,咱們須要拿到用戶信息,並將用戶信息存儲在session
中,方便咱們隨時取用。那要怎麼作呢?這裏咱們須要編寫一箇中間件來實現這個功能。代碼以下:前端
// app/middleware/eggJwt module.exports = options => { return async function jwt(ctx, next) { const token = ctx.request.header.authorization; if (token) { // 這裏有個坑,前端通常傳過來是Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoieGl... // 可是解碼時不須要Bearer,因此須要手動處理一下 const tokenStr = token.split(' ')[1]; try { // 解碼token並存儲到session中 const decode = ctx.app.jwt.verify(tokenStr, options.secret); ctx.session.user = decode; await next(); } catch (error) { ctx.status = 500; ctx.body = { message: error.message }; return; } } else { ctx.status = 401; ctx.body = { message: '用戶未登陸' }; return; } }; };
這裏說明一下eggjs
的插件機制,若是你在config.default.js
中配置:java
config.middleware = ['eggJwt'];
那麼,這個插件將做用於全部的路由,除非有特殊配置,可是這裏咱們不須要,因此不加這一行代碼。咱們按需配置:shell
// app/router.js module.exports = app => { const { router, controller } = app; const jwt = 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('/login', controller.user.login); };
咱們手動引入後按需配置便可。數據庫
這個時候咱們去訪問配置了jwt的接口,就會執行插件,解析token
,並將解析結果存儲到session
裏。咱們修改一下user controller
的代碼試一下:安全
async getUsers() { // 打印session console.log(this.ctx.session.user, '==========='); const users = await this.ctx.model.User.findAll(); this.ctx.body = { code: 200, data: users }; }
配置好token後請求localhost:7001/getUsers
,數據能正常返回,同時控制檯打印出了:session
{ name: 'xiaoming', iat: 1609055716, exp: 1609062916 } ===========
能夠看到這時咱們就拿到了token
裏存儲的數據。app
按照咱們如今的代碼,若是咱們須要調整model
中的字段,咱們須要修改model
文件,而後再寫腳本同步修改數據庫中的字段,這樣太麻煩了。幸虧,Sequelize
提供了一個方法讓咱們能夠根據model
去同步數據庫裏的字段:async
User.sync()
- 若是表不存在,則建立該表(若是已經存在,則不執行任何操做)User.sync({ force: true })
- 將建立表,若是表已經存在,則將其首先刪除User.sync({ alter: true })
- 這將檢查數據庫中表的當前狀態(它具備哪些列,它們的數據類型等),而後在表中進行必要的更改以使其與模型匹配.
注意咱們這裏只能用User.sync({ alter: true })
,那麼要在何時去執行呢?咱們想在每次服務啓動時去同步數據庫字段,同時eggjs也提供了生命週期供咱們使用:函數
// app.js class AppBootHook { constructor(app) { this.app = app; } configWillLoad() { // 此時 config 文件已經被讀取併合並,可是還並未生效 // 這是應用層修改配置的最後時機 // 注意:此函數只支持同步調用 } async didLoad() { // 全部的配置已經加載完畢 // 能夠用來加載應用自定義的文件,啓動自定義的服務 } async willReady() { // 全部的插件都已啓動完畢,可是應用總體還未 ready // 能夠作一些數據初始化等操做,這些操做成功纔會啓動應用 // 根據model同步數據庫 await this.app.model.sync({ alter: true }); } async didReady() { // 應用已經啓動完畢 } async serverDidReady() { // http / https server 已啓動,開始接受外部請求 // 此時能夠從 app.server 拿到 server 的實例 } } module.exports = AppBootHook;
這時,咱們在user model
中新增一個字段:nickname: STRING(10)
,而後重啓一下服務,打開數據庫看看user
表,果真多了一個nickname
的列。這個功能極大地方便了咱們去同步model
與數據庫字段,可是操做的時候也要當心,不要誤刪字段。
這一篇內容很少,可是都是很實用的功能,下一篇咱們將經過Sequelize
來實現表的關聯查詢。