jwt鉴权机制

1、摘要

JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本质就是一个字符串书写规范,作用是用来在用户和服务器之间传递安全可靠的信息。

2. JWT是什么

根据维基百科的定义,JSON WEB Token(JWT,读作 [/dʒɒt/]),是一种基于JSON的、用于在网络上声明某种主张的令牌(token)。JWT通常由三部分组成: 头信息(header), 消息体(payload)和签名(signature)。

在目前前后端分离的开发过程中,使用token鉴权机制用于身份验证是最常见的方案,流程如下

Image.png

  1. 假设用户要登录一个APP,用户就需要输入用户名和密码,然后发送给APP的服务器
  2. 服务器验证过用户发来的用户名和密码后,就会生成一个token,
  3. 服务端返回JWT信息给用户,JWT中
  4. 用户发送请求的时候一般会在HTTP头部加上这个Token
  5. 服务器收到Token后,对Token进行核实,Token验证通过,且没有过期
  6. 用户直接登录,不需要再次输入用户名密码,服务器只需识别头部的Token就可以确认用户身份

这里生成的Token就用的JWT这种数据结构

✒️Token的携带
token可以放在Cookie,Authorization,或者Body里面

什么情况下使用JWT比较适合?

3. JWT 的数据结构

Token,分成了三部分,头部(Header)、载荷(Payload)、签名(Signature),并以.进行拼接。其中头部和载荷都是以JSON格式存放数据,只是进行了base64 编码(secret 部分是否进行 base64 编码是可选的,header 和 payload 则是必须进行 base64 编码),由于编码过程是可逆的,如果得知编码方式后,那么整个 jwt 串便是明文了,所以pyaload中一定不能放密码等重要信息。

Image [2].png

头部主要是用来指明签名的算法,避免消息被篡改,jwt 中常用的签名算法是 HS256,常见的还有md5,sha 等,签名算法是不可逆的。声明算法的字段名为alg,同时还有一个typ的字段,默认JWT即可。以下示例中算法为HS256,

1
{"alg": HS256, "typ": "JWT"}

pyaload

负载主要是用来存放数据,一般可以存放相应用户数据来生成不同的JWT

1
2
3
4
5
6
7
8
9
  "payload": {
"data": [
{
"tooltt": "https://tooltt.com"
}
],
"iat": 1650451633,
"exp": 1650556799
}

JWT规定了7个官方字段,供选用

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。

1
2
3
4
5
6

{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

由于编码的可逆性,不要把秘密信息放在这个部分。

Signature

签名是对头部和负载两个部分进行签名,防止数据篡改。
签名里面有个核心就是要定义一个密钥,这个密钥只有服务器能知道,然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
公式如下:

1
2

Signature = HMACSHA256(base64Url(header)+.+base64Url(payload),secretKey)

一旦前面两部分数据被篡改,只要服务器加密用的密钥没有泄露,得到的签名肯定和之前的签名不一致

4. 鉴权机制时如何实现的

相关代码已上传github https://github.com/blueskyadd/JWT

基础服务器的搭建

首先初始化项目

1
npm init -y

Image [3].png

第二步 安装 express jsonwebtoken依赖

1
npm i express jsonwebtoken -D

Image [4].png

第三步,调整配置文件
为了方便我们本地调试代码,安装nodemon

nodemon用来监视node.js应用程序中的任何更改并自动重启服务,非常适合用在开发环境中

1
npm i nodemon -D

打开pakage.json文件调整scripts,调试命令

Image [5].png

然后创建app.js文件

Image [6].png

监听3000端口,运行npm run egg启动服务

登录生成JWT

借助第三方库jsonwebtoken,通过jsonwebtoken 的 sign 方法生成一个 token

  • 第一个参数指的是 Payload
  • 第二个是秘钥,服务端特有
  • 第三个参数是 option,可以定义 token 过期时间

此处的密钥,使用crypto来生成30位的随机字符串

Image [7].png

然后来尝试调用接口,我这里使用的是REST Client 插件,可以直接安装,
然后创建一个以http结尾的文件

Image [8].png

然后点击send Request 发送请求,请求成功后,可以看到返回的信息

Image [9].png

校验token

使用jwt.verify(token,secretOrPublicKey,[options,callback])来
验证token的合法性;

Image [10].png

同理发送get请求,将登录返回的token, 复制到请求头的authorization字段上,拼接Bearer 空格 token 这是遵守OAuth2.0规则的

然后点击发送,返回认证成功的信息

Image [11].png

5. JWT的优缺点

优点

  • json具有通用性,所以可以跨语言组成简单,
  • 字节占用小,便于传输服务端无需保存会话信息,
  • 很容易进行水平扩展一处生成,多处使用,
  • 可以在分布式系统中,
  • 解决单点登录问题可防护CSRF攻击

缺点

  • payload部分仅仅是进行简单编码,所以只能用于存储逻辑必需的非敏感信息
  • 需要保护好加密密钥,一旦泄露后果不堪设想
  • 为避免token被劫持,最好使用https协议

6. 推荐阅读

JWT介绍及其安全性分析

Posted on

2022-03-27

Updated on

2022-08-03

Licensed under

Kommentare

:D 一言句子获取中...

Loading...Wait a Minute!