node开发api,使用jsonwebtoken实现token验证

 0 1条评论

前后端分离是基本是目前项目的趋势,客户端和服务端如何通讯,session,cookie,token等等,有太多方法了。以下是百度来的两者的区别。

1. 好处

那Token相对于Cookie的好处:

支持跨域访问: Cookie是不允许垮域访问的,token支持

无状态: token无状态,session有状态的

去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在 你的API被调用的时候, 你可以进行Token生成调用即可.

更适用于移动应用: Cookie不支持手机端访问的

性能: 在网络传输的过程中,性能更好

基于标准化: 你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在 多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如: Firebase,Google, Microsoft)

2 缺陷

说了那么多token认证的好处,但他其实并没有想象的那么神,token 也并不是没有问题。

1. 占带宽

正常情况下要比 session_id 更大,需要消耗更多流量,挤占更多带宽,假如你的网站每月有 10 万次的浏览器,就意味着要多开销几十兆的流量。听起来并不多,但日积月累也是不小一笔开销。实际上,许多人会在 JWT 中存储的信息会更多。

2. 无法在服务端注销,那么就很难解决劫持问题

3. 性能问题

JWT 的卖点之一就是加密签名,由于这个特性,接收方得以验证 JWT 是否有效且被信任。但是大多数 Web 身份认证应用中,JWT 都会被存储到 Cookie 中,这就是说你有了两个层面的签名。听着似乎很牛逼,但是没有任何优势,为此,你需要花费两倍的 CPU 开销来验证签名。对于有着严格性能要求的 Web 应用,这并不理想,尤其对于单线程环境。

其实咋看一下,都不是很清楚说啥。说说我实际开发中的经验,token就是服务端派发的一个通行证,只要有了这个通行证的访客,通行证可以复制,可以给任何人,有通行证的人都可以访问服务端给定的资源。服务端只对token这段字符进行验证,合法即为通过。

而session只保留在单一的客户端,访客关闭客户端即失效,但是session需要一个用户登录过程,不登入如何判断客户的唯一性?而token是无状态的,就是一串字符串,再怎么加密,对于客服来说就是一大串字符串,服务端在对这段字符串就行解密,判断是否合法,获取payload载荷。

在前后端分离的项目中,token是唯一的选择,至于如何实现token的安全唯一性,可以通过redis来解决,这篇文章不多阐述,这里仅仅记录一下,如下在node下实现token通讯。

一,安装apenssl,这里就不阐述安装过程了,安装成功后,进入bin目录,打开openssl.exe。


会出来命令行,然后输入:

kcs8 -topk8 -inform PEM -in 文件名.pem -outform PEM –nocrypt

然后在bin目录下就会生成此文件,打开一下就是如此界面:


二,继续在命令行输入以下指令:

rsa -in 刚才的文件名.pem -pubout -out rsa_public_key.pem

至此公钥密钥都生成了,把这两个文件复制到node项目中,如下图:


三,npm安装jsonwebtoken模块,然后新建一个JWT.js的文件,封装一下,我这里是吧密钥都放在全局变量中了,实际开发中可以根据自己情况来定夺,代码如下:

// 引入模块依赖
import jwt from 'jsonwebtoken'

// iss:Issuer,发行者
// sub:Subject,主题
// aud:Audience,观众
// exp:Expiration time,过期时间
// nbf:Not before
// iat:Issued at,发行时间
// jti:JWT ID

/**
 * 根据载荷生成token,返回生成的token等信息
 *
 * @param {object} payload
 * @return {string}
 * @public
 */
export const generateToken = (payload, expiresIn) => {
    let createtime = Math.floor(Date.now() / 1000)
    //payload.iat = createtime
    payload.iss = 'hzkjseat'
    //payload.exp = createtime + expiresIn
    // console.log(payload)
    const cert = global.config.tokenPrivateKey //从全局变量里读取,
    let access_token = jwt.sign(
        { payload },
        cert,
        { expiresIn, algorithm: 'RS256' }
    )
    return {
        access_token,//token
        iat:createtime,//发行时间
        exp:createtime + expiresIn//过期时间
    }
}

/**
 * 验证token,验证成功则返回载荷
 * @param {string} token
 */
export const verifyToken = async (token) => {
    try {
        let cert = global.config.tokenPublicKey
        let data = (jwt.verify(token, cert, { algorithm: 'RS256' })) || {}
        return data
    } catch (e) {
        throw e
    }
}

四,用户使用凭证,我项目中是通过id和apikey来获取凭证的,代码如下(仅仅是示例):

export default async (req, res, next) => {
    const { id, key } = req.query
    if (!ObjectID.test(id) || !ApiKey.test(key)) {
        next(ApiKeyFail)
    }
    const tokenExpiresIn = 60 * 60 * 4 // 单位秒 设置token过期时间和redis本身一致
    const result =generateToken({name:'shuanghei'},tokenExpiresIn)
    next(result)
}

最后,然后设定一个路由守卫,所有请求必须先通过此中间件。


代码如下:

import {verifyToken } from '../utils/JWT.js'

export default  async (req, res, next) => {
    let reqtoken = req.headers.authorization
    console.log(verifyToken(reqtoken))//判断token是否合法
    next()
}

这次,初步完成node项目下,token的通讯了,具体业务逻辑,还需要根据项目需求来修改。


本文作者:双黑

版权声明:本站文章欢迎链接分享,禁止全文转载!

游客