zoukankan      html  css  js  c++  java
  • koa2+redis+jwt token验证,简单注册登录

    首先新建文件夹命名koa-server,npm init,相关包的安装就不说了,这是我的package.json

    新建index.js文件,编码如下,config全局配置不用管,redis是一个简单的get和set操作的封装,也不用管

    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_data

    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接口的访问

    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和register

    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数据库必须有数据

    或者/api/register注册,存一个新的

    验证token只需要新建一个js,比如排行榜rank.js,如果前端没有在header中设置token或者token设置为不存在的,则会返回401,token error

    前端附加token必须是(以vue、axios为例)

     大胆尝试是进步的主力,如果连尝试都不去,那什么也做不成,就像有钱人的儿子都很有钱一样,你穷并不是因为你代码写的不好,而是因为世界是不和平的,所以活出自己吧!

  • 相关阅读:
    Linux系列教程-----Linux安装centos6.8
    laravel 常见操作
    git 拖下laravel 代码后报错 Warning: require(D:WWWlaravelootstrap/../vendor/autoload.php
    phpunit单元测试
    linux环境配置
    window 环境下在虚拟机上安装php环境
    第三方登录---微信(使用laravel插件)
    h5页面在ios机上禁止长按复制
    JS 中根据iframe子页面自动iframe高度
    关于JS解析编历JSON数组(含多维数组)
  • 原文地址:https://www.cnblogs.com/wangzisheng/p/11362793.html
Copyright © 2011-2022 走看看