一文读懂 JWT!

原文链接: https://programercat.blog.csdn.net/article/details/101283512


作者 | 喵叔

责编 | 胡巍巍

出品 | 程序人生(ID:coder_life)

JWT 英文名是 Json Web Token ,是一种用于通信双方之间传递安全信息的简洁的、URL安全的表述性声明规范,经常用在跨域身份验证。
JWT 以 JSON 对象的形式安全传递信息。因为存在数字签名,因此所传递的信息是安全的。
在讲解 JWT 之前我们先来看一个问题。我们都知道 Internet 服务的身份验正过程是这样的,客户端向服务器发送登录名和登录密码,服务器验证后将对应的相关信息保存到当前会话中,这些信息包括权限、角色等数据。
服务器向客户端返回 Session ,Session 信息都会写入到客户端的 Cookie 中,后面的请求都会从 Cookie 中读取 Session 发送给服务器,服务器在收到 Session 后会对比保存的数据来确认客户端身份。
但是上述模式存在一个问题,无法横向扩展。在服务器集群或者面向服务且跨域的结构中,需要数据库来保存 Session 会话,实现服务器之间的会话数据共享。
在单点登录中我们会遇到上述问题,当有多个网站提供同一拨服务,那么我们该怎么实现在甲网站登陆后其他网站也同时登录呢?
其中一种方法是持久化 Session 数据,也就是上面所说的将 Session 会话存到数据库中。这个方法的优点是架构清晰明了。
但是缺点也非常明显,就是架构修改很困难,验证逻辑需要重写,并且整体依赖于数据库,如果存储 Session 会话的数据库挂掉那么整个身份认证就无法使用,进而导致系统无法登录。要解决这个问题我们就用到了 JWT 。

在这里插入图片描述

JWT 简述

客户端身份经过服务器验证通过后,会生成带有签名的 JSON 对象并将它返回给客户端。客户端在收到这个 JSON 对象后存储起来。
在以后的请求中客户端将 JSON 对象连同请求内容一起发送给服务器,服务器收到请求后通过 JSON 对象标识用户,如果验证不通过则不返回请求的数据。
验证不通过的情况有很多,比如签名不正确、无权限等。在 JWT 中服务器不保存任何会话数据,使得服务器更加容易扩展。

在这里插入图片描述

Base64URL 算法

在讲解 JWT 的组成结构前我们先来讲解一下 Base64URL 算法。这个算法和 Base64 算法类似,但是有一点区别。
我们通过名字可以得知这个算法使用于 URL 的,因此它将 Base64 中的 + 、 / 、 = 三个字符替换成了 - 、 _ ,删除掉了 = 。因为这个三个字符在 URL 中有特殊含义。

在这里插入图片描述

JWT 组成结构

JWT 是由三段字符串和两个 . 组成,每个字符串和字符串之间没有换行(类似于这样:xxxxxx.yyyyyy.zzzzzz),每个字符串代表了不同的功能,我们将这三个字符串的功能按顺序列出来并讲解:

  1. JWT 头
    JWT 头描述了 JWT 元数据,是一个 JSON 对象,它的格式如下:
    一文读懂 JWT!_第1张图片
    这里的 alg 属性表示签名所使用的算法,JWT 签名默认的算法为 HMAC SHA256 , alg 属性值 HS256 就是 HMAC SHA256 算法。typ 属性表示令牌类型,这里就是 JWT。

  2. 有效载荷
    有效载荷是 JWT 的主体,同样也是个 JSON 对象。有效载荷包含三个部分:

①标准注册声明

标准注册声明不是强制使用是的,但是我建议使用。它一般包括以下内容:
iss:jwt的签发者/发行人;
sub:主题;
aud:接收方;
exp:jwt过期时间;
nbf:jwt生效时间;
iat:签发时间
jti:jwt唯一身份标识,可以避免重放攻击

②公共声明:

可以在公共声明添加任何信息,我们一般会在里面添加用户信息和业务信息,但是不建议添加敏感信息,因为公共声明部分可以在客户端解密。

③私有声明:

私有声明是服务器和客户端共同定义的声明,同样这里不建议添加敏感信息。
下面这个代码段就是定义了一个有效载荷:
一文读懂 JWT!_第2张图片
3. 哈希签名
哈希签名的算法主要是确保数据不会被篡改。它主要是对前面所讲的两个部分进行签名,通过 JWT 头定义的算法生成哈希。哈希签名的过程如下:

  1. 指定密码,密码保存在服务器中,不能向客户端公开;
  2. 使用 JWT 头指定的算法进行签名,进行签名前需要对 JWT 头和有效载荷进行 Base64URL 编码,JWT 头和邮箱载荷编码后的结果之间需要用 . 来连接。
    简单示例如下:
    在这里插入图片描述
    最终结果如下:
    在这里插入图片描述
    在这里插入图片描述

JWT 注意事项

在使用 JWT 时需要注意以下事项:

  1. JWT 默认不加密,如果要写入敏感信息必须加密,可以用生成的原始令牌再次对内容进行加密;
  2. JWT 无法使服务器保存会话状态,当令牌生成后在有效期内无法取消也不能更改;
  3. JWT 包含认证信息,如果泄露了,任何人都可以获得令牌所有的权限;因此 JWT 有效期不能太长,对于重要操作每次请求都必须进行身份验证。

在这里插入图片描述

JWT 例子

  1. 自定义 JWT
    定义 JWT 头
    在这里插入图片描述
    定义有效载荷
    在这里插入图片描述
    加密 JWT 头和有效载荷
    生成哈希签名
    在这里插入图片描述
    按顺序链接三部分,最终形成 JWT:
    在这里插入图片描述
    完整代码如下:
    一文读懂 JWT!_第3张图片一文读懂 JWT!_第4张图片
    一文读懂 JWT!_第5张图片
    运行结果如下:
    [外链图片转存失败(img-lRLSRgqS-1569462704127)(https://s2.ax1x.com/2019/09/18/nosk7V.png)]
  2. 使用 .NET JWT 包
    上面的代码我们在造轮子,但是 NuGet 中已经有造好的轮子了。在 NuGet 中搜索 JWT 并安装。使用 JWT 包我们只需要自定义有效载荷和密码即可,可生成三段格式的字符串
    JWT 生成代码如下:
    一文读懂 JWT!_第6张图片
    同样,我们可以利用 JWT 包对生成的 JWT 进行解密,代码如下:
    一文读懂 JWT!_第7张图片
    上述代码在项目中可以直接拿来用,只需修改其中的有效载荷和密码。

在这里插入图片描述

总结

本篇首先讲解了 JWT 的相关知识,然后通过自定义的方式和调用 JWT 包的方式手动创建了 JWT 。文章所讲的内容大家一定要切记,这些知识在开发中至关重要,在最后再补充两个小知识:

  1. 客户端发送 JWT 发送给服务器时,最好把 JWT 放在HTTP请求的Header Authorization,格式是:Authorization: Bearer jwt。
  2. JWT 不仅仅可以实现身份认证还可以在跨域 post 请求时将请求参数加入到有效载荷中,实现 post 跨域请求。

作者简介:朱钢,笔名喵叔,CSDN博客专家,.NET高级开发工程师,7年一线开发经验,参与过电子政务系统和AI客服系统的开发,以及互联网招聘网站的架构设计,目前就职于北京恒创融慧科技发展有限公司,从事企业级安全监控系统的开发。CSDN博客地址:https://programercat.blog.csdn.net/
【END】
一文读懂 JWT!_第8张图片

你可能感兴趣的:(一文读懂 JWT!)