JWT 底层原理与使用

转载

前言

HTTP 协议是一种无状态的协议,这意味着用户提供账号和密码进行登录认证后,下次再请求的时候,仍然需要认证,因为服务器并不知道是谁发送的请求,并不知道该用户已经认证过一次了。
所以为了解决这个问题,保持客户端和服务端的会话状态,在服务器的缓存中需要为每一位用户分配存储空间,用于存储用户的个人登录信息等。且没份存储空间有个唯一标识ID作为自己的身份证。
这样在作响应的时候,将该ID返回给浏览器,浏览器存储到本地,以便后续再次请求时都可以携带着这个ID,服务器就能根据这个ID去对应缓存空间中去查找是否存在对应的缓存区,能找到则表示该用户之前已经访问过了,存储区存储的登录信息也可以直接使用,就不用再次登陆了。

这就是传统的session + cookie 的会话保持技术,session 是存在于服务端的一个缓存区,相当于一个存储数据的map数据结构,每个session 对应着自己的session ID,而cookie 则是存在于客户端浏览器的一种数据存储区。

上述流程实际上是浏览器的第一次访问服务器的时候分配session 空间和生成session ID,并将session ID存储在响应头的Set-Cookie ;浏览器会专门处理Cookie数据并进行存储,在下一次发请求的时候会在请求头的Cookie字段携带之前存储的cookie数据,也就是sessionID,服务器会在收到请求后先在请求头中的cookie 拿到这个ID,这样后续就能找到和操作专属这个用户的数据存储区了。

基于Session 的会话保持技术存在很多弊端

  • 随着用户增多服务器的开销也会显然增大
  • 在处理分布式应用的情境下会相应的限制负载均衡器的能力
  • Cookie存储在客户端,如果被拦截窃取,会很容易收到CSRF跨域伪造请求攻击
  • 除浏览器外的其他设备对Cookie的支持并不友好,对跨平台支持不友好

Jwt 概述

JWT 的出现就是为了解决传统Session + Cookie 技术存在的各种问题,实际上随着前后端分离的发展,以及数据中心的建立,越来越多的公司会创建一个中心服务器,同时服务于各种产品线,如:统一身份认证平台,这些产品线上的产品,他们可能有各种终端设备,包括但不仅限于浏览、桌面应用、移动端应用、平板应用、甚至于智能家居。
JWT 底层原理与使用_第1张图片
JWT(json web token),json格式的网络令牌,简称token,它要解决的问题,就是为多种终端设备,提供统一的、安全的令牌格式。

因此,JWT 只是一个令牌格式而已,你可以把他存储到cookie,也可以存储到localstorage,没有任何限制。同样的,对于传输,你可以使用任何传输方式来传输JWT,一般来说,我们会使用HTTP消息头来传输他(header 的 Authorization)

当客户端拿到令牌后,存储他即可。可以存到各种位置,比如手机文件、PC文件、local storage、Cookie等。当后续请求发生时,你只需要将他作为请求的一部分发送到服务器即可。

这样一来,服务器就能收到这个令牌,通过对令牌的验证,即可知道该令牌是否有。他们的完整交互流程是非常简单清晰的!
JWT 底层原理与使用_第2张图片

组成

JWT是可以存储用户信息的,自定义一个用户信息的结构体里面自己带一些信息然后拿整个结构体区生成token
JWT 底层原理与使用_第3张图片

1、Header

Header 是一个令牌头部,记录了整个令牌的类型和签名算法,格式是一个json对象。
签名算法有两种。
对称加密和非对称加密
JWT 底层原理与使用_第4张图片
设置好了header 的结构之后,还需要对header 的JSON 对象进行Base64 URL编码,最后编码生成的字符串才是header 部分。

注意:Base64 URL 不是一个加密算法,而是一种编码格式,它是在Base64 算法的基础上对 + = / 三个字符做出特殊处理的一种变种算法。而Base64 是使用64个可打印字符来表示一个二进制数据。

2、Payload

这部分是JWT 主体信息,仍然是一个JSON 对象
JWT 底层原理与使用_第5张图片
实际上就是存用户信息的,通常都自定义一个结构,其实payload 只是一个JSON对象,如下也是一个有效的payload!
JWT 底层原理与使用_第6张图片
payload 部分也和 header一样,需要通过Base64 URL 编码。

3、Signature(重点)

这一部分是 JWT 的签名,正是因为这部分的存在,保证了整个JWT不被篡改。这部分的生成方式与上述两部分直接编码JSON对象不同,他需要将前面两部分的编码结果通过.连接起来,然后按照头部指定的加密方式进行加密(结合自定义的密钥)

最后,将三部分通过 . 组合在一起,就得到了完整的JWT。并且由于签名使用的密钥保证存在服务器,客户端就无法伪造出签名。JWT无法伪造的本质就在于第三部分,因为前两部分并没有加密,只是一个编码结果,可以几乎认为是明文传输的。这个没有问题,因为登陆成功后是可以查看自己的个人信息的。

4、令牌检验

JWT的signature 如何保证令牌不被篡改呢

若用户人为的修改payload中的个人信息再进行编码发送到服务器,服务器如何识别呢。

1、对header + payload 用同样的密钥和加密算法进行加密
2、然后把加密的结果和传入的JWT 的signature 进行对比,如果完全相同那么就没被篡改

当令牌验证为没有被篡改之后,服务器可以进行其他验证,比如是否过期、听众是否满足要求等。

这些验证都由服务器手动完成,不会自动验证,你也可以通过第三方库来完成这些操作

JWT 使用

Gin 框架对JWT的封装
JWT 底层原理与使用_第7张图片

JWT 底层原理与使用_第8张图片

关于 Token 有效期的续期方案

如果想设置Token 长时间有效,可以采用redis 的方式。

  1. 将token 存储在redis 中,设置过期时间,token如果没有过期则自动刷新redis的过期时间。
  2. 通过这种方式,可以很方便的对token续期,而且也可以实现长时间不登陆,强制登陆
  3. 并且redis存取速度非常快,可以快速验证token的有效与否

JWT 底层原理与使用_第9张图片

用户信息类

JWT 底层原理与使用_第10张图片
作为生成Token的参数
不论如何自定义什么结构体,必须带有标准库提供的 claim,里面有签名 ,有效期等必要信息

自定义一些信息

JWT 底层原理与使用_第11张图片

生成Token

JWT 底层原理与使用_第12张图片
其中jwt.NewWithClaims new一个token,他有两个参数,返回值就是token

  • 第一个是加密方法,这里使用的是jwt.SigningMethodHS256 另一种非对称加密上文有提及。
  • 第二个是加密的一些参数,可以使用自带的jwt.MapClaims,也可以自定义一个结构体,如果是自定义一个结构体需要实现jwt.StandardClaim 结构体,里面可以定义过期时间颁发者等。

验证Token

JWT 底层原理与使用_第13张图片
这里的IsContainArr作用是排除掉那些不需要验证权限的路由。
这个验证不是解析,可有可无只是get出来一些值并且插入其中

解析Token

JWT 底层原理与使用_第14张图片
这里使用类型断言去转成我们定义的结构体类型,claims本质上是一个接口,由token包定义的(由token包定义的)

解密使用jwt.Parse方法,如果上面使用了自己定义的结构体的话就使用jwt.ParseWithClaims方法

jwt.Parse有两个参数

  • 第一个就是加密后的token字符串
  • 第二个是一个自带的回调函数,将密钥和错误return出来即可

jwt.ParseWithClaims有三个参数

  • 第一个就是加密后的token字符串
  • 第二个是加密使用的模板,就是传入一个空的自定义结构体
  • 第三个是一个自带的回调函数,将密钥和错误return出来即可

更新Token

JWT 底层原理与使用_第15张图片

更新操作目的在于延长token

你可能感兴趣的:(Go,golang,后端)