JWT(JSON Web Token)

要解决的问题:跨域认证问题

互联网服务的用户认证流程:

  • 用户向服务器发送用户名和密码;
  • 服务器验证通过后,在当前会话session里面保存相关数据,比如用户角色,登陆时间等;
  • 服务器向用户返回一个session_id,写入用户的Cookie;
  • 用户随后的每一次请求都会携带Cookie,将session_id传回服务器。
  • 服务器收到session_id后,根据他找到之前保存的该用户的信息,得知用户身份。

缺点

  • 扩展性不好。单机当然没有问题,如果是服务器集群,或是跨域的服务导向架构,就要求session数据共享,要求每台服务器都能够读取到session;
  • 占用服务器资源。需要服务器来保存用户的信息,如果在千万级数据量下,会很耗服务器资源;

解决方案

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

了解JWT

原理

服务器认证以后,生成一个JSON对象,发回给用户:

{
  "姓名": "张三",
  "角色": "管理员",
  "到期时间": "2018年7月1日0点0分"
}

以后,用户与服务端通信的时候,都要发回这个JSON对象,服务器完全只靠这个对象认定用户身份。为了发哪个会用户篡改数据,服务器在生成这个对象的时候,会加上签名。

服务器就不用保存任何session数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

什么是服务器有无状态?

有状态服务:服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求处理,典型的设计如tomcat的session;
缺点:

  1. 服务端保存大量数据,增加服务端压力;
  2. 服务端保存用户状态,无法进行水平扩展;
  3. 客户端请求依赖服务端,多次请求必须访问同一台服务器;

有状态服务:微服务集群中的每个服务,对外提供的都是Rest风格的接口,而Rest风格的一个最重要的规范就是服务的无状态性,即服务端不保存任何客户端请求者信息,客户端的每次请求必须具备自描述信息,通过这些信息识别客户端身份。
优点:

  1. 客户端请求不依赖服务端信息,任何多次请求不需要必须访问到同一台服务;
  2. 服务端请求集群和状态对客户端透明,即对客户端来将集群相当于只有一台服务器;
  3. 服务端可以任意的迁移和伸缩;
  4. 减小服务端存储压力;

JWT的数据结构

实际上的JWT大概是这样的:

在这里插入图片描述
它是一个很长的字符串,中间用点.分割成三个部分,JWT内部是没有换行的;

三个部分依次如下:

  • Header(头部)
  • Payload(负载)
  • Signature(签名)
    在这里插入图片描述

Header

Header部分是一个JSON对象,描述JWT的元数据

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

其中,alg代表签名的算法,默认是HMAC SHA256(HS256);typ属性表示这个令牌(token)的类型;最后将这个JSON对象使用Base64URL算法转成字符串;

Payload

Payload部分也是一个JSON对象,用来存放实际需要传递的数据

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

还可以在这个部分定义私有字段

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

注意:JWT默认是不加密的,任何人都能读到,所有不要把私密信息放在这个部分。这个JSON对象也要使用Base64URL算法转成字符串。

Signature
在这里插入图片描述
Signature部分是对前两部分的签名,防止数据篡改。

首先,需要制定一个密钥(secret),这个密钥只有服务器知道,不能泄露给用户,然后使用Header里面指定的签名算法,按照下面的公式产生签名:

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

算出签名后,把Header、Payload、Signature三部分拼成一个字符串,每个部分用.分割,就可以返回给客户。

签名的目的

在这里插入图片描述
如果有人对头部以及载荷的内容解码之后在进行修改,然后再进行编码,那么新的头部和载荷计算出来的签名和这个JWT内的签名就是不一致的。 而对jwt的签名如果不知道加密的密钥,是不能修改的。

服务器应用在接受到JWT之后,会首先对头部和载荷的内容用同一种算法再次签名,如果服务器应用对头部和载荷再次以同样算法签名之后发现,自己计算出来的签名和接收到的签名不一样,那就说明这个Token的内容被别人动过,我们应该拒绝这个Token,返回一个HTTP401 Unauthorized响应。

JWT交互流程

在这里插入图片描述

  1. 用户登录;
  2. 服务的认证,通过后根据secret生成token;
  3. 将生成的token返回给浏览器;
  4. 用户每次请求携带token
  5. 服务器端解读jwt签名,判断有效后,从Payload中获取用户信息;
  6. 处理请求,返回响应结果。

因为JWT签发的token中已经包含了用户身份信息,并且每次请求都会携带,这样服务端就无需保存用户信息,甚至无需在取数据库查询,完全符合Rest的无状态规范。

JWT的几个特点

  • JWT默认是不加密的,但是也可已加密,生成原始Token之后,可以用密钥再加密一次;
  • JWT不加密的情况下,不能将秘密数据写入JWT;
  • JWT不仅可以用于认证,也可以用于交换信息,有效使用JWT,可以降低服务器查询数据库的次数;
  • JWT的最大缺点是,由于服务器不保存session状态,因此无法在使用过程中废止某个token,或者更改token的权限。也就是说,一旦JWT签发了,在到期之前就会始终有效,除非服务器部署额外逻辑;
  • JWT本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置的比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
  • 为了减少盗用,JWT不应该使用HTTP协议明码传输,要使用HTTPS协议传输
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值