koa2+redis+jwt token驗證,簡單註冊登陸

首先新建文件夾命名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

 

 大膽嘗試是進步的主力,若是連嘗試都不去,那什麼也作不成,就像有錢人的兒子都頗有錢同樣,你窮並非由於你代碼寫的很差,而是由於世界是不和平的,因此活出本身吧!

相關文章
相關標籤/搜索