JsonWebToken

   概述   

若是各位不了解 JWT,没关系张,它并不可怕。前端

JSON Web Token(JWT)是一个很是轻巧的规范。这个规范容许咱们使用JWT在用户和服务器之间传递安全可靠的信息。算法

让咱们来假想一下一个场景。在A用户关注了B用户的时候,系统发邮件给B用户,而且附有一个连接“点此关注A用户”。连接的地址能够是这样的json

https://www.xxxx.com/make-friend/?from_user=B&target_user=A

  组成  

一个JWT实际上就是一个字符串,它由三部分组成,头部载荷签名后端

    载荷(Payload)    

咱们先将上面的添加好友的操做描述成一个JSON对象。其中添加了一些其余的信息,帮助从此收到这个JWT的服务器理解这个JWT。安全

 
  
{
"iss": "LiuzhichaoJWT",
"iat": int(time.time()),
"exp": expire_time,
"aud": "luffy",
"sub": "target@example.com",
"from_user": "B",
"target_user": "A"
}

这里面的前五个字段都是由JWT的标准所定义的。服务器

  • iss: 该JWT的签发者cookie

  • sub: 该JWT所面向的用户session

  • aud: 接收该JWT的一方前后端分离

  • exp(expires): 何时过时,这里是一个Unix时间戳分布式

  • iat(issued at): 在何时签发的

这些定义均可以在标准中找到。

将上面的JSON对象进行[base64编码]能够获得下面的字符串。这个字符串咱们将它称做JWT的Payload(载荷)。

eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9
# 载荷
expire_time = int(time.time() + 10)

payload = {
    "iss": "LiuzhichaoJWT",
    "iat": int(time.time()),
    "exp": expire_time,
    "aud": "luffy",
    "sub": "target@example.com",
    "from_user": "B",
    "target_user": "A"
}

json_payload = base64.urlsafe_b64encode(json.dumps(payload).encode("utf-8"))

print(json_payload)
载荷

    头部(Header)    

JWT还须要一个头部,头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也能够被表示成一个JSON对象。

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

在这里,咱们说明了这是一个JWT,而且咱们所用的签名算法(后面会提到)是HS256算法。

对它也要进行Base64编码,以后的字符串就成了JWT的Header(头部)。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
import json
import base64


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

base64.urlsafe_b64encode(json.dumps(headers).encode("utf-8")).replace(b'=', b'')
Python实现

    签名(签名)    

将上面的两个编码后的字符串都用句号 .链接在一块儿(头部在前),就造成了

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9

最后,咱们将上面拼接完的字符串用HS256算法进行加密。在加密的时候,咱们还须要提供一个密钥(secret)。若是咱们用 `liuzhichao` 做为密钥的话,那么就能够获得咱们加密后的内容

rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
# 密钥
key = "liuzhichao"

string = b".".join([header_string, json_payload])

# 签名
sign = base64.urlsafe_b64encode(hmac.new(key.encode("utf-8"), string, hashlib.sha256).digest())

print(sign)
获取签名实现

这一部分又叫作签名

 

最后将这一部分签名也拼接在被签名的字符串后面,咱们就获得了完整的JWT

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM

因而,咱们就能够将邮件中的URL改为

https://www.xxx.com/make-friend/?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM

这样就能够安全地完成关注好友的操做了!

且慢,这里你们思考下有什么问题没有:

  • 签名的目的是什么?
  • Base64是一种编码,是可逆的,那么信息不就被暴露了吗?

    签名的目的    

  最后一步签名的过程,其实是对头部以及载荷内容进行签名。通常而言,加密算法对于不一样的输入产生的输出老是不同的。对于两个不一样的输入,产生一样的输出的几率极其地小(有可能比我成世界首富的几率还小)。因此,咱们就把“不同的输入产生不同的输出”当作必然事件来看待吧。

  因此,若是有人对头部以及载荷的内容解码以后进行修改,再进行编码的话,那么新的头部和载荷的签名和以前的签名就将是不同的。并且,若是不知道服务器加密的时候用的密钥的话,得出来的签名也必定会是不同的。

 

  服务器应用在接受到JWT后,会首先对头部和载荷的内容用同一算法再次签名。那么服务器应用是怎么知道咱们用的是哪种算法呢?别忘了,咱们在JWT的头部中已经用 alg字段指明了咱们的加密算法了(并且 JWT 在后端建立以后,只留下加密方式,不会保存.在传给前端)。

  若是服务器应用对头部和载荷再次以一样方法签名以后发现,本身计算出来的签名和接受到的签名不同,那么就说明这个Token的内容被别人动过的,咱们应该拒绝这个Token,返回一个HTTP 401 Unauthorized响应。

缺点 

1.信息容易暴露

  在JWT中,不该该在载荷里面加入任何敏感的数据。在上面的例子中,咱们传输的是用户的User ID。这个值实际上不是什么敏感内容,通常状况下被知道也是安全的。可是像密码这样的内容就不能被放在JWT中了。若是将用户的密码放在了JWT中,那么怀有恶意的第三方经过Base64解码就能很快地知道你的密码了。

2.注销问题 : 

  与传统的cookie+session相比较,用户想要主动注销,那么在服务端中清除便可.

  可是因为 JWT 是无状态的,服务端经过计算进行校验,是不进行存储的,即便是在客户端清除,服务端仍是在有效期内的.

  解决 : 

    1).由于jwt是放在客户端的cookie中,清除cookie便可.

    2).清空或者修改服务器中的用户对应的secret,这样在用户注销后,可是因为secret不存在或者改变,则没法完成校验.

 

为何用 jwt 

  为何用jwt而不是用session,与session相比较,jwt的优势 : 

  1).适合分布式,先后端分离.优点在于服务端不存储任何会话,用户传递的信息经过token解析---分布式 

    (就像 阿里与菜鸟驿站的关系)

相关文章
相关标签/搜索