前端也有必要了解JWT吗?

  • Post author:
  • Post category:其他




什么是JWT

JWT全称是JSON WEB TOKEN,是一种基于JSON的开放标准(RFC 7519),主要用于用户与服务器之间安全地传输信息。简单的说,JWT就是一种认证机制。



推荐

文章将率先在公众号「

Code满满

」与个人博客「


李益的小站


」上发布,如果本文对你有帮助,就关注一下公众号吧!



什么是认证

HTTP协议本身是一种无状态的协议,在应用程序中,用户需要输入用户名和密码来进行用户认证,获取属于用户自己的信息。但是如果每次都要用户输入用户名和密码,就太过于繁琐了;于是就有了

Session认证



Token认证



传统的Session认证

Session是一种记录客户端和服务器端会话状态的机制,是基于Cookie实现的,其认证流程如下:

  1. 客户端第一次请求服务器,服务器根据客户端提交的信息,创建对应的Session
  2. 服务器一般将Session保存在内存中,然后将SessionID返回给客户端
  3. 客户端收到SessionID后,会将SessionID保存在Cookie中,并记录此SessionID属于哪个域名
  4. 客户端第二次请求时,会将此域名下的Cookie信息发送给服务器,服务器获取Cookie信息后,会从中提取出SessionID并去查找自己保存的对应的Session;如果找到,则说明认证成功,否则认证失败

Session有如下缺陷:

  • 因为Session一般保存在服务器的内存中,随着用户增多,服务器的开销会越来越大
  • 因为Session是存在内存中,会带来一些扩展性问题
  • 因为是基于Cookie来进行用户识别的, Cookie如果被截获,用户就会很容易受到CSRF攻击(跨站请求伪造攻击)



传统的Token认证

传统的Token认证流程如下:

  1. 客户端输入用户名和密码来请求服务器,服务器会根据客户端提交的信息,创建一个Token
  2. 服务器会将Token存储在数据库中或者缓存起来,然后将Token返回给客户端
  3. 客户端收到Token后会保存在本地,并在每次请求时带上Token,一般会放在请求的Header中
  4. 服务器会从请求信息中获取Token,并去查库验证Token是否有效

这种基于Token的认证是无状态的,能有效的防止CSRF攻击,但是这种认证方式不是没有缺陷,比如:每次服务器验证Token是否有效时都要去查库,这也是一种消耗;另外,客户端退出登录时也必须调用接口来通知服务器删除Token,比较繁琐。



JWT认证

JWT是目前主流的认证方式,其认证流程如下:

  1. 客户端输入用户名和密码来请求服务器,服务器根据客户端提交的信息,会创建一个Token,并返回给客户端,自己不会保存这个Token
  2. 客户端获取Token后会保存在本地,每次请求时都带上Token,一般会放在请求的Header中
  3. 服务器获取请求信息中的Token后,会直接解析这个Token,从中获取用户的相关信息,不用去查库;如果解析成功,则代表认证成功,否则代表Token无效,认证失败

JWT认证与传统的Token认证不同的地方在于:JWT认证的Token是交由客户端保管的,服务器端一般不存储Token;服务器验证Token是否有效是通过能否直接解析Token来判断的,如果能解析,则表示有效,否则无效。这样做的好处,就是服务器不用存储Token,不用查库,减少开销;在分布式或者多服务器的应用中,每个服务器都可以直接判断Token是否有效并解析,而不必去单独访问一个专门存储Token的服务器,扩展性得到很大提升。

从上述内容中可以明显看出,JWT认证的强大之处在于可以从Token中解析出有用的数据,而不像传统的Token,仅仅是一个身份标识。下面我们就看一下,JWT是怎样构成的。



构成

JWT共有三部分构成:


  • Header(头部)

  • Payload(负载)

  • Signature(签名 )



Header(头部)

头部一般会记录两种信息:

  • 声明Token的类型,一般声明为

    JWT
  • 声明加密算法名称,一般声明为

    HMAC

    、**SHA256 **等

完整案例如下:

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

然后将头部信息使用Base64编码,构成Token的第一部分。



Payload(负载)

负载是存放有效信息的地方,包含三种声明:

Registered claims(注册声明)

,

Public claims(公共声明)

以及

Private claims(私有声明)

  • 注册声明:一组预定义的声明,不强制,但推荐


    • iss (issuer)

      :jwt签发者

    • sub (subject)

      :jwt所面向的用户

    • aud (audience)

      :接收jwt的一方

    • iat (issued at)

      :jwt的签发时间

    • exp (expiration)

      :jwt的过期时间,这个过期时间必须要大于签发时间

    • nbf (not before)

      :声明jwt在指定的时间后有效

    • jti (JWT ID)

      :jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击(如果JWT标识存在,那么发出者不能复用同一JWT标识,如果一JWT的jti声明与另一JWT完全相同,则被视为重放攻击)
  • 公共的声明:可以添加任何的信息,一般添加用户的相关信息或其它业务需要的信息,但不建议添加敏感信息

  • 私有的声明:一般是签发者和接收者所共同定义的声明,不建议存放敏感信息

完整案例如下:

{
	"iss": "www.liyisite.com"
	"sub": "1234567890",
	"exp": 1618400868
	"user_id": "1",
	"username": "liyi",
}

对Payload进行Base64编码就得到JWT的第二部分。



Signature(签名 )

JWT的第三部分是一个签名信息,它是用Header中指定的那个签名算法对编码过的Header、编码过的Payload以及一个秘钥进行签名,从而生成的。

签名是用于验证消息在传递过程中有没有被更改;并且,对于使用私钥签名的token,它还可以验证JWT的发行者是否为它所指定的发行者。



缺陷

JWT虽然有种种好处,但是也有缺陷。因为JWT是一经签发,在未到期前都是有效的,加上token是存放在客户端,所以服务器无法废弃token。这意味着如果token被他人获取,即使签发新token,只要旧token未到失效时间,就依然有效,他人依然可以使用,这是非常危险的。

此时,后端一般会使用Redis等工具来缓存签发的jwt,设立黑名单,当签发新的jwt后,就会把旧jwt放入黑名单,直至旧jwt失效后,从缓存中移除。不过如此一来,就有点违背JWT的原则了。



版权声明:本文为liyi1009365545原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。