如何用Eggjs從零開始開發一個項目(3)

上一篇中咱們編寫了用戶註冊登陸、登陸的代碼,學習瞭如何進行用戶的認證(JWT),如何安全地存儲用的密碼(hash)。這一篇咱們有如下2個任務:javascript

  1. 獲取token中的數據;
  2. 經過model來同步數據庫。

獲取token中的數據

用戶登陸的時候咱們已經用戶的一些基本信息加密存儲到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中的字段,咱們須要修改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來實現表的關聯查詢。

相關文章
相關標籤/搜索