首先新建文件夾命名koa-server,npm init,相關包的安裝就不說了,這是個人package.json前端
新建index.js文件,編碼以下,config全局配置不用管,redis是一個簡單的get和set操做的封裝,也不用管vue
const bodyParser = require("koa-bodyParser"); const Koa = require("koa"); const koaStatic = require("koa-static"); const path = require("path"); const cors = require("koa2-cors"); const koaJwt = require('koa-jwt'); // const const token = require("./model/paytoken") const constroller = require("./controller"); const config = require("./model/config"); const db = require("./model/redis"); const app = new Koa(); //全局配置 global.config = config; global.db = db; global.secret = "tokensecret"; //設置靜態目錄 app.use(koaStatic(path.resolve(__dirname,"./public"))); //跨域 app.use(cors()); //post 參數解析 app.use(bodyParser()); //token驗證是否過時或失效 app.use(token); //容錯處理 app.use((ctx,next)=>{ return next().catch((error)=>{ if(error.status === 401){ ctx.status = 401; ctx.body = { code:-1, msg:"token error 401" } } else{ throw error; } }); }); //token過濾規則 app.use(koaJwt({secret:global.secret}).unless({ path:[ /^\/api\/login/, /^\/api\/register/, /^((?!\/api).)*$/ ] })); //導入controller middleware app.use(constroller()); //啓動 app.listen(config.port); console.log(`server start at 3000`);
其中paytoken是token的解析與驗證,在這裏能夠獲取加密的相關信息,如userid等,這裏保存到ctx上下文,保證是本次請求,命名token_dataios
const jwt = require('jsonwebtoken'); async function verify(ctx,next){ let url = ctx.request.url; let authorization = ctx.request.headers["authorization"]; if(authorization){ let token = authorization.split(" ")[1]; let payload = jwt.verify(token,global.secret,(error,decoded)=>{ if(error){ ctx.body = { status:-1, msg:"登錄失效" }; } else{ ctx.token_data = decoded; return next(); } }); } else{ return next(); } } module.exports = verify;
controller是路由控制,主要用於路由自動解析,原理是掃描controllers文件夾下的全部js文件,同時對其require導出,規則是必須導出前綴爲"PSOT "或"GET "的路由,用於api接口的訪問web
const fs = require("fs"); function addMapping(router,mapping){ for(let url in mapping){ if(url.startsWith('GET')){ //若是url相似get xxx let path = url.substring(4); router.get(path,mapping[url]); } else if(url.startsWith("POST")){ //若是url 相似post xxx let path = url.substring(5); router.post(path,mapping[url]); } else{ console.log(`invalid URL:${url}`); } } } function addControllers(router,dir){ let files = fs.readdirSync(__dirname + "/" + dir); //過濾js文件 let js_files = files.filter((f)=>{ return f.endsWith(".js"); }); //處理每一個js文件 for(let f of js_files){ let mapping = require(__dirname + '/controllers/' + f); addMapping(router,mapping); } } module.exports = function(dir){ let controllers_dir = dir || "controllers"; let router = require("koa-router")(); addControllers(router,controllers_dir); return router.routes(); }
controllers文件夾下新建sign.js文件,處理login和registerredis
const jwt = require('jsonwebtoken'); const db = global.db; //註冊路由 let register_func = async (ctx,next)=>{ let name = ctx.request.body.userName; let password = ctx.request.body.password; let userdata = {name,password}; let body; if(!name || !password){ body = { code:-1, msg:"用戶名或密碼不能爲空" } } else if(name.length < 4){ body = { code:-1, msg:"用戶名長度必須大於等於4" } } else if(password.length < 8){ body = { code:-1, msg:"密碼至少爲8位" } } else{ let data = await db.getKey(name); if(data){ body = { code:-1, msg:"用戶名重複", } } else{ let result = await db.setKey(name,JSON.stringify(userdata)); if(result == "OK"){ body = { code:0, msg:"註冊成功", token:jwt.sign(userdata,global.secret,{expiresIn:'4h'}) } } else{ body = { code:-1, msg:"註冊失敗,緣由未知" } } } } ctx.body = body; } //登陸路由 let login_func = async (ctx,next)=>{ let name = ctx.request.body.userName || ""; let password = ctx.request.body.password || ""; if(!name || !password){ ctx.body = { code:-1, msg:"用戶名或密碼錯誤" } } else{ let result = await db.getKey(name); let body; if(!result){ body = { code:-1, msg:"用戶不存在" } } else{ let data = JSON.parse(result); if(data.password === password){ body = { code:0, msg:"登陸成功", token:jwt.sign({name,password},global.secret,{expiresIn:'4h'}) } } else{ body = { code:-1, msg:"密碼錯誤" } } } ctx.body = body; } } module.exports = { "POST /api/login":login_func, "POST /api/register":register_func }
其中生成簽名token代碼以下數據庫
jwt.sign(userdata,global.secret,{expiresIn:'4h'})
接下來post請求/api/login,傳入參數成功則生成token返回給客戶端,不然失敗,注意redis數據庫必須有數據npm
或者/api/register註冊,存一個新的json
驗證token只須要新建一個js,好比排行榜rank.js,若是前端沒有在header中設置token或者token設置爲不存在的,則會返回401,token erroraxios
前端附加token必須是(以vue、axios爲例)api
大膽嘗試是進步的主力,若是連嘗試都不去,那什麼也作不成,就像有錢人的兒子都頗有錢同樣,你窮並非由於你代碼寫的很差,而是由於世界是不和平的,因此活出本身吧!