Eggjs笔记:关于JWT的接口权限验证

关于接口的安全验证

  • 基于 Session 的安全验证
    • Session 存储在服务器,用户用户比较少的话是一种简单的安全验证机制,但是涉及到跨域 的话需要进行一些配置
    • 用户量非常非常大的话会耗费一定的服务器资源(中小项目不需要考虑)
  • 对请求参数进行加密的签名验证
    • 涉及公钥、私钥、签名等
  • JWT
    • JWT 全称 JSON Web Token,是目前比较流行的另一种跨域身份验证解决方案
    • 也是被很多人用坏的一种安全验证机制,具体需要看项目是否适合

关于 JWT的验证的流程

  • 客户端请求接口登录,登录成功后,服务端通过jwt生成token返回给客户端
  • 客户端访问需要登录后才能访问的接口的时候,需要在请求接口的时候携带token,服务端获取token调用jwt验证token的合法性,验证不通过则拒绝访问

Nodejs 中使用 JWT 实现接口的安全验证

签发 token

安装 jsonwebtoken $ cnpm install jsonwebtoken --save

签发:

var jwt = require('jsonwebtoken'); 
router.get('/login', function (req, res, next) {
    // 三个参数:用户对象,签名字符串(最好定义在配置中),过期时间
    var token = jwt.sign({ name: '张三' }, 'this is sign',{ expiresIn:60*60*24});
    res.send(token);
});

Axios 访问基于 Jwt 的接口

// 存储服务器签发的token ... 
var token = ''; // 这是保存的服务器签发的token, 伪代码

// 带token请求接口
axios.get("http://localhost:3000/api/list", {
    auth: {
        username: token,
        password:''
    }
}) 
.then(function(response) {
    // handle success
    console.log(response); })
.catch(function(error) {
    // handle error
    console.log(error); 
    })
.finally(function() {
    // always executed
});

备注:在不同的框架中如:react,vue,angular, 需要封装通用拦截器,在拦截器中使用,以上仅作为演示

获取请求头里面的 token

安装 $ cnpm install basic-auth --save

获取

router.get('/addressList', function (req, res, next) { 
    var token = auth(req); // 这里的auth就是 basic-auth
})

验证客户端传过来 token 的合法性

router.get('/addressList', function (req, res, next) { 
    var token = auth(req);
    if(!token) {
        res.send('没有权限'); 
    }
    
    try {
        var v = jwt.verify(token.name, 'this is sign'); // 验证token
        // console.log(v);
        res.send(v ? "有权限" : "没有权限")
    } catch (error) { 
        res.send(error);
    } 
});

备注:上面仅作为简单演示,最好做成一个中间件来处理权限验证

关于 Jwt 的一些问题

  • JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
  • JWT 不加密的情况下,不能将秘密数据写入 JWT。
  • JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询 数据库的次数。
  • JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个token,或者更改 token 的权限。也就是说,一旦JWT签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
  • JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
  • 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

关于jwt的二次签名验证

  • 对于某一个接口,如: /api/address?uid=1&pid=2, 对请求的参数进行签名, “uid=1&pid=2”,通过算法处理 var sign = md5(“uid=1&pid=2” + 私钥) , 这个私钥可以是个md5加密后的登录密码
  • 这个时候客户端会有这三个东西: token, 请求的url参数, sign (也就是 前面的password)
  • 服务端获取客户端携带的token以及url上的参数, 然后比如根据uid查找用户密码, 计算出私钥(私钥=md5(用户密码)), 然后计算出sign
  • 对比客户端传递过来的sign和服务端计算出的sign是否一致, 如果一致则验证通过
  • 当另一个接口被请求的时候,如:/api/xxx?uid=1&tid=3 同样的道理,每次因为参数不同,计算出的sign都是不一样的,当然如果没有参数,接口本身其实也可以当做参数处理, 服务器可以通过相同的算法来进行对比,这样可以进一步阻止了客户端权限的盗用
  • 当然道高一尺魔高一丈,没有绝对的安全,如果涉及到一些支付相关的业务, 尽量利用二次加密和https以及尽可能小的过期时间,以及做一些机制对token进行续签等

猜你喜欢

转载自blog.csdn.net/Tyro_java/article/details/106583547