JWT学习

her~~llo,我是你们的好朋友Lyle,是名梦想成为计算机大佬的男人!

博客是为了记录自我的学习历程,加强记忆方便复习,如有不足之处还望多多包涵!非常欢迎大家的批评指正。

 学习JWT之前呢,我们先来看看传统Session。

传统的Session认证

1、用户向服务器发送用户名和密码。

2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。

3、服务器向用户返回一个 session_id,写入用户的 Cookie。

4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。

5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份

Session认证暴露的问题

①用户认证后在服务端做一次session记录,以方便下次鉴别,通常而言session都是保存在内存中,用户越多,服务端开销会增大;
②认证的记录被保存在内存中,用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源。在分布式的应用上,限制了负载均衡器的能力。以此限制了应用的扩展能力;
③session是基于cookie来进行用户识别,cookie如果被截获,用户很容易受到CSRF(跨站伪造请求攻击)攻击;
④跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现?

两种解决方案:

①是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。
②不再保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。

JWT与Session的区别

相同点:都是存储用户信息;

不同点:①Session是在服务器端的,而JWT是在客户端的。

②Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销。

而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。

③Session的状态是存储在服务器端,客户端只有session id;

而Token的状态是存储在客户端。

JWT认证流程

①前端通过Web表单将自己的用户名和密码发送到后端的接口。一般是HTTP的POST请求。建议通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。
②后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT(Token)。
③后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage(浏览器本地缓存)或sessionStorage(session缓存)上,退出登录时前端删除保存的JWT即可。
④前端在每次请求时将JWT放入HTTP的Header中的Authorization位。(解决XSS和XSRF问题)
⑤后端检查是否存在,若存在,验证JWT的有效性。
⑥验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。

JWT结构

token令牌,是一个String字符串,由3部分组成,中间用点隔开

就像这样:aaaa.bbbb.cccc

这三部分分别为:

第一部分为标头(Header)

第二部分为有效载荷(Payload)

第三部分为签名(Header).

前两部分都使用Base64进行编码

标头(Header)

包含令牌的类型和所使用的签名算法,如HMAC、SHA256、RSA。

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

有效载荷(Payload)

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明

标准中注册的声明 :

iss: jwt签发者
sub: 主题
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 生效时间
iat: 签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

公共的声明 :

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。该部分在客户端可解密,不建议添加敏感信息

私有的声明 :

私有声明是提供者和消费者所共同定义的声明。该部分在客户端可解密,不建议添加敏感信息

签名(Header)

签名的过程实际上是对头部以及负载内容进行签名,防止内容被窜改。如果有人对头部以及负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成新的JWT的话,那么服务器端会判断出新的头部和负载形成的签名和JWT附带上的签名是不一样的。


这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,再与secret通过header中声明的加密方式进行组合加密,然后就构成了jwt的第三部分。

例:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

也就是该部分包含三部分:

  • header (base64加密后的)
  • payload (base64加密后的)
  • secret

你可能感兴趣的:(JWT)