轉載請告知並註明來源做者
做者
:唐金健
網絡暱稱
:御焱
掘金
知乎
思否
專欄
:優雅的前端
Microsoft Visual Studio 2017
集成開發環境Node.js v8.9.4
Javascript運行環境 如下是基本的代碼,實現靜態服務器,以及一個當token驗證異常時候的處理。
下面咱們將在這個基本代碼下逐步增長註冊、登陸、信息的功能。css
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()} 服務器已經啓動!`); });
下面,咱們將在註冊、登陸、信息的註釋底下添加實現的代碼。html
註冊、登陸接口、其它資源不須要認證,信息接口須要認證。前端
/* 路由權限控制 */ 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以後,能夠保存在任意本地存儲裏。web
/* 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]
字段。數據庫