乐趣区

44-权限拦截控制\AccessToken-jwt博客后端ApiNodeJsExpressMysql实战

权限控制

业务需求:查看用户列表接口(管理员才能使用)、更新用户信息接口(当前对应用户才能调用)

这时候需要需要加入中间件来实现权限控制:

这时候咱们需要学习了解下:AccessToken jwt

AccessToken jwt

课前学习了解
JSON Web Token 入门教程
http://www.ruanyifeng.com/blo…
基于 jsonwebtoken(JWT)的 web 认证 (Node 版实现)
https://segmentfault.com/a/11…
node-jsonwebtoken
https://github.com/auth0/node…

本文中使用了 node-jsonwebtoken@7.2.1 插件

现将 token 服务逻辑代码附上

/**
 * token 服务
 * add by boomer 2019-05-03 21:57:11
 */
var Promise = require("bluebird");
var config = require('config-lite'); // 配置
var jwt = require('jsonwebtoken'); //json token

module.exports = {
    /**
     * 设置 token 创建 token
     */
    setToken: function(payload) {// var expiresIn = Math.floor(Date.now() / 1000) + (1 * 60); // var expiresIn = '24h';
        var expiresIn = Date.now() + 3600000 * 24;//24 小时后
        var token = jwt.sign(payload, config.token.secretOrPrivateKey, {expiresIn: expiresIn, // 设置过期时间});
        return {
            token: token,
            expiresIn: expiresIn,
        };
    },
    /**
     * 验证 token 是否正确:传入当前 token 和当前用户 uuid
     */
    verifyToken: function(token, userUuid){return new Promise(function(resolve, reject) {jwt.verify(token, config.token.secretOrPrivateKey, function(err, tokenData) {if (tokenData && tokenData.uuid == userUuid) {resolve('ok');
                }else{reject('fail');
                }
            });
        });
    },
    /**
     * 路由验证 token
     */
    verifyRouterToken: function(req, res, next, isAdmin) {
        //accesstoken 被自动转小写了
        var token = req.headers.accesstoken;
        if (!token) { // 如果没有 token,则返回错误
            res.json({code: "401",});
            return;
        } else { // 验证 token
            jwt.verify(token, config.token.secretOrPrivateKey, function(err, tokenData) { // 只有在 token 正确时 tokenData 有值
                if (err) {
                    res.json({code: "402",});
                    return;
                } else {
                    // 验证是否为管理员
                    if (isAdmin && !tokenData.isAdmin) {
                        res.json({code: "403",});
                        return;
                    } else if (!isAdmin && tokenData.uuid && !tokenData.isAdmin) {
                        // 验证 userUuid 避免普通用户登录修改其他人资料
                        var userUuid = (req.body || req.query || req.params)['userUuid'];
                        if (userUuid && userUuid != tokenData.uuid) {
                            res.json({code: "403",});
                            return;
                        } else {next();
                        }
                    } else {next();
                    }
                }
            });
        }
    },
    /**
     * 清除 token
     */
    delToken: function(token) {if (!token) {return 'delTokenFail';} else {jwt.decode(token);
            return 'delTokenSuccess';
        }
    },
};

accessToken 一般在登录 / 注册成功时获取 然后缓存到本地,每次前端请求时将有效的 accessToken 放到 headers 中,然后请求到后端,后端再通过校验 token 中间件做权限拦截,校验通过后才能执行后面的业务逻辑(这块后面写前端时补充)
现在说下,后端通过上面 tokenService.setToken 方法 生成 AccessToken 的代码:

退出移动版