Node.js的Koa實現JWT用戶認證

版權聲明

轉載請告知並註明來源做者
做者唐金健
網絡暱稱御焱
掘金 知乎 思否 專欄優雅的前端css

1、前置知識

2、環境

  • Microsoft Visual Studio 2017集成開發環境
  • Node.js v8.9.4Javascript運行環境

3、開始動手,一步步來完善

一、建立基礎的靜態資源服務器、基礎架構

  如下是基本的代碼,實現靜態服務器,以及一個當token驗證異常時候的處理。
  下面咱們將在這個基本代碼下逐步增長註冊、登陸、信息的功能。html

const path    = require('path');         // 用於處理目錄路徑
const Koa     = require('koa');          // web開發框架
const serve   = require('koa-static');   // 靜態資源處理
const route   = require('koa-route');    // 路由中間件
const jwt     = require('jsonwebtoken'); // 用於簽發、解析`token`
const jwtKoa  = require('koa-jwt');      // 用於路由權限控制
const koaBody = require('koa-body');     // 用於查詢字符串解析到`ctx.request.query`
const app     = new Koa();

const website = {
    scheme: 'http',
    host: 'localhost',
    port: 1337,
    join: function () {
        return `${this.scheme}://${this.host}:${this.port}`
    }
}

/* jwt密鑰 */
const secret = 'secret';

/* 當token驗證異常時候的處理,如token過時、token錯誤 */
app.use((ctx, next) => {
    return next().catch((err) => {
        if (err.status === 401) {
            ctx.status = 401;
            ctx.body = {
                ok: false,
                msg: err.originalError ? err.originalError.message : err.message
            }
        } else {
            throw err;
        }
    });
});

/* 查詢字符串解析到`ctx.request.query` */
app.use(koaBody());

/* 路由權限控制 */
// 待辦事項……

/* POST /api/register 註冊 */
// 待辦事項……

/* GET /api/login 登陸 */
// 待辦事項……

/* GET /api/info 信息 */
// 待辦事項……


/* 靜態資源處理 */
app.use(serve(path.join(__dirname, 'static')));
/* 監聽服務器端口 */
app.listen(website.port, () => {
    console.log(`${website.join()} 服務器已經啓動!`);
});
複製代碼

  下面,咱們將在註冊、登陸、信息的註釋底下添加實現的代碼。前端

二、路由權限控制

  註冊、登陸接口、其它資源不須要認證,信息接口須要認證。web

/* 路由權限控制 */
app.use(jwtKoa({ secret: secret }).unless({
    // 設置login、register接口,能夠不須要認證訪問
    path: [
        /^\/api\/login/,
        /^\/api\/register/,
        /^((?!\/api).)*$/   // 設置除了私有接口外的其它資源,能夠不須要認證訪問
    ]
}));
複製代碼

三、註冊

/* POST /api/register 註冊 */
app.use(route.post('/api/register', async (ctx, next) => {
    const body = ctx.request.body;
    /* * body = { * user : '御焱', * password : '123456' * } */

    // 判斷 body.user 和 body.password 格式是否正確
    // 待辦事項……

    // 判斷用戶是否已經註冊
    // 待辦事項……

    // 保存到新用戶到數據庫中
    // 待辦事項……

    // 是否註冊成功
    let 是否註冊成功 = true;
    if (是否註冊成功) {
        // 返回一個註冊成功的JOSN數據給前端
        return ctx.body = {
            ok: true,
            msg: '註冊成功',
            token: getToken({ user: body.user, password: body.password })
        }
    } else {
        // 返回一個註冊失敗的JOSN數據給前端
        return ctx.body = {
            ok: false,
            msg: '註冊失敗'
        }
    }
}));
/* 獲取一個期限爲4小時的token */
function getToken(payload = {}) {
    return jwt.sign(payload, secret, { expiresIn: '4h' });
}
複製代碼

三、登陸

/* GET /api/login 登陸 */
app.use(route.get('/api/login', async (ctx, next) => {
    const query = ctx.request.query;
    /* * query = { * user : '御焱', * password : '123456' * } */

    // 判斷 query.user 和 query.password 格式是否正確
    // 待辦事項……

    // 判斷是否已經註冊
    // 待辦事項……
    
    // 判斷姓名、學號是否正確
    // 待辦事項……
    
    return ctx.body = {
        ok: true,
        msg: '登陸成功',
        token: getToken({ user: query.user, password: query.password })
    }
}));
複製代碼

  前端獲取到token以後,能夠保存在任意本地存儲裏。

四、信息

/* GET /api/info 信息 */
app.use(route.get('/api/info', async (ctx, next) => {
    // 前端訪問時會附帶token在請求頭
    payload = getJWTPayload(ctx.headers.authorization)
    /* * payload = { * user : "御焱", * iat : 1524042454, * exp : 1524056854 * } */

    // 根據 payload.user 查詢該用戶在數據庫中的信息
    // 待辦事項……
    const info = {
        name: '御焱',
        age: 10,
        sex: '男'
    }
    let 獲取信息成功 = true;
    if (獲取信息成功) {
        return ctx.body = {
            ok: true,
            msg: '獲取信息成功',
            data: info
        }
    } else {
        return ctx.body = {
            ok: false,
            msg: '獲取信息失敗'
        }
    }
}));
/* 經過token獲取JWT的payload部分 */
function getJWTPayload(token) {
    // 驗證並解析JWT
    return jwt.verify(token.split(' ')[1], secret);
}
複製代碼

  訪問須要認證的接口時,須要在 request頭附帶 Authorization:Bearer [token]字段。
相關文章
相關標籤/搜索