JsonWebToken(jwt)用法及其优势

jsonwebtoken

具体的实践可以看我github上的例子

用法

jwt.sign(payload, secretOrPrivateKey, [options, callback])

(异步)如果提供回调,则使用err或JWT 调用回调。

(同步)将JsonWebToken返回为字符串。

payload必须是一个object, buffer或者string。请注意, exp只有当payload是object字面量时才可以设置。
secretOrPrivateKey 是包含HMAC算法的密钥或RSA和ECDSA的PEM编码私钥的string或buffer。
options:

  • algorithm:加密算法(默认值:HS256)

  • expiresIn:以秒表示或描述时间跨度zeit / ms的字符串。如60,"2 days","10h","7d",Expiration time,过期时间

  • notBefore:以秒表示或描述时间跨度zeit / ms的字符串。如:60,"2days","10h","7d"

  • audience:Audience,观众

  • issuer:Issuer,发行者

  • jwtid:JWT ID

  • subject:Subject,主题

  • noTimestamp

  • header

如果payload不是buffer或string,它将被强制转换为使用的字符串JSON.stringify()。
在expiresIn,notBefore,audience,subject,issuer没有默认值时。也可以直接在payload中用exp,nbf,aud,sub和iss分别表示,但是你不能在这两个地方同时设置。
请记住exp,nbf,iat是NumericDate类型。
生成的jwts通常会包含一个iat值除非指定了noTimestamp。如果iat插入payload中,则将使用它来代替实际的时间戳来计算其他事情,诸如options.expiresIn给定一个exp这样的时间间隔。

 

// sign with default (HMAC SHA256)
var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
//backdate a jwt 30 seconds
var older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');

// sign with RSA SHA256
var cert = fs.readFileSync('private.key');  // get private key
var token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'});

// sign asynchronously
jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256' }, function(err, token) {
  console.log(token);
});

Token Expiration (exp claim)

签署1小时期限的token:

 

jwt.sign({
  exp: Math.floor(Date.now() / 1000) + (60 * 60),
  data: 'foobar'
}, 'secret');

使用此库生成令牌的另一种方法是:

 

jwt.sign({
  data: 'foobar'
}, 'secret', { expiresIn: 60 * 60 });

//or even better:

jwt.sign({
  data: 'foobar'
}, 'secret', { expiresIn: '1h' });

jwt.verify(token,secretOrPublicKey,[options,callback])

验证token的合法性

jwt.decode(token [,options])

(同步)返回解码没有验证签名是否有效的payload。
警告:这不会验证签名是否有效。你应该不为不可信的消息使用此。你最有可能要使用jwt.verify()。

错误与代码

TokenExpiredError
如果令牌过期,则抛出错误。
错误对象:

  • name:'TokenExpiredError'

  • message:'jwt expired'

  • expiredAt:[ExpDate]

JsonWebTokenError
错误对象:

  • name:'JsonWebTokenError'

  • message:

    • jwt异常

    • jwt签名是必需的

    • 无效签名

    • jwt观众无效 预期:[OPTIONS AUDIENCE]

    • jwt发行人无效。预期:[OPTIONS ISSUER]

    • jwt id无效。预期:[OPTIONS JWT ID]

    • jwt主题无效。预期:[OPTIONS SUBJECT]


JWT应用场景?

简介中提到两个场景,我认为主要第一种--身份认证。为什么采用这种方式呢?我总结了下

1、json格式简单,相比xml,我更喜欢json;Self-contained,一般都翻译成自包含,意思是jwt中已经有了你需要的全部信息,拿出来用就行。

2、同session相比,性能更好一些,省去了处理分布session的问题;对于大行其道的restful来讲,支持得很好;浏览器+app+pc,这种多终端开发,是很好的选择。

JWT有什么好处?

1、支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.

2、无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.

4、更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.

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

6、更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。

7、CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。

8、性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.

9、不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.

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

补充:Base64URL
这个算法跟 Base64 算法基本类似,但有一些小的不同。
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。

 

### 缓存 Token 的最佳实践 在 Node.js 环境下,缓存 Token 是一种常见的需求,尤其是在涉及身份验证的应用程序中。以下是几种常用的缓存方法及其优缺点分析。 #### 使用内存存储(如 `Map` 或 `Object`) 对于简单的应用场景,可以直接使用 JavaScript 原生的数据结构来缓存 Token。这种方法适合小型项目或测试环境,因为它不需要额外依赖外部服务。 ```javascript const tokenCache = new Map(); function cacheToken(token, data) { const expirationTime = Date.now() + (data.expireIn * 1000); // 转换为毫秒 tokenCache.set(token, { ...data, expiresAt: expirationTime }); } function getTokenData(token) { const cachedData = tokenCache.get(token); if (!cachedData || cachedData.expiresAt < Date.now()) { tokenCache.delete(token); // 清理过期的 Token return null; } return cachedData; } ``` 这种方式的优点在于简单易用且性能高[^1],但由于数据仅存在于内存中,在服务器重启后会丢失所有缓存内容。 --- #### 使用 Redis 进行分布式缓存 Redis 是一个高性能的键值数据库,非常适合用来缓存 Token 数据。它支持持久化、TTL(时间至活)设置以及跨多台机器共享缓存的能力。 安装并连接 Redis: ```bash npm install redis ``` 代码示例: ```javascript const redis = require('redis'); const client = redis.createClient(); // 创建 Redis 客户端实例 client.on('error', (err) => console.error(`Redis Client Error: ${err}`)); // 存储 Token 到 Redis 并设置 TTL function cacheTokenToRedis(token, data) { const ttlInSeconds = data.expireIn; // 单位:秒 client.SETEX(token, ttlInSeconds, JSON.stringify(data)); } // 获取 Token 数据 function getTokenFromRedis(token, callback) { client.GET(token, (err, result) => { if (err) throw err; if (!result) return callback(null, null); // 如果没有找到对应的 Token,则返回 null try { const parsedResult = JSON.parse(result); callback(null, parsedResult); } catch (e) { callback(e, null); } }); } ``` 通过 Redis 实现缓存的优势在于其强大的扩展性和可靠性[^2],尤其适用于需要在多个节点之间共享状态的服务架构。 --- #### 结合 JWT 和缓存机制优化认证流程 当使用 JsonWebToken 模块生成和解析 Token 时,可以通过缓存进一步提升效率。例如,可以在首次成功验证 Token 后将其保存到缓存中,并在未来请求中优先查询缓存而不是重新计算签名。 ```javascript const jwt = require('jsonwebtoken'); async function verifyAndCacheToken(token) { let cachedData = await getTokenFromRedis(token); // 尝试从 Redis 中获取已缓存的 Token if (cachedData) { return Promise.resolve(cachedData); // 若存在则直接返回 } return new Promise((resolve, reject) => { jwt.verify(token, 'your-secret-key', async (err, decoded) => { if (err) return reject(err); // 验证成功后将 Token 缓存起来 await cacheTokenToRedis(token, decoded); resolve(decoded); }); }); } ``` 此方案不仅减少了重复计算的工作量,还增强了系统的响应速度[^3]。 --- ### 总结 - 对于单机部署的小型应用,可以选择基于内存的方式快速实现 Token 缓存功能。 - 当面对更复杂的场景或者分布式的系统设计时,推荐采用 Redis 来管理 Token 缓存。 - 在实际开发过程中,应综合考虑业务特点和技术栈特性选取最适合的技术手段。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值