Microsoft Visual Studio 2017
集成開發環境Node.js v8.9.4
Javascript運行環境 如下是基本的代碼,實現靜態服務器,以及一個當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 })
}
}));
複製代碼
/* 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]
字段。