Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景。JWT的声明通常被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也能够增长一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。web
咱们知道,http协议自己是一种无状态的协议,而这就意味着若是用户向咱们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,由于根据http协议,咱们并不能知道是哪一个用户发出的请求,因此为了让咱们的应用能识别是哪一个用户发出的请求,咱们只能在服务器存储一份用户登陆的信息,这份登陆信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给咱们的应用,这样咱们的应用就能识别请求来自哪一个用户了。算法
HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码便可,但因为有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的愈来愈少。所以,在开发对外开放的RESTful API时,尽可能避免采用HTTP Basic Auth。数据库
OAuth(开放受权)是一个开放的受权标准,容许用户让第三方应用访问该用户在某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。json
OAuth容许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每个令牌受权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户能够受权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非全部内容
下面是OAuth2.0的流程:浏览器
Cookie认证机制就是为一次请求认证在服务端建立一个Session对象,同时在客户端的浏览器端建立了一个Cookie对象;经过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理的。默认的,当咱们关闭浏览器的时候,cookie会被删除。但能够经过修改Cookie 的expire time使cookie在必定时间内有效;
缓存
JWT (Json Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。安全
JWT的声明通常被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。好比用在用户登陆上。服务器
有些朋友可能会认为,我登陆只须要用缓存或者数据库记录下一个特征码或者是Cookies就能够了,为何要使用JWT呢?咱们知道一个数据库或者是一个软件,损耗时间最大的地方就是咱们的 I/O(输入输出,一般指的就是硬盘的读写),所以咱们选择解码一次HS256,对于如今的计算能力强大的计算机而言,解一次HS256比访问一次磁盘要快得多。cookie
基于token的鉴权机制相似于http协议也是无状态的,它不须要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不须要去考虑用户在哪一台服务器登陆了,这就为应用的扩展提供了便利。
流程上是这样的:
网络
这个token必需要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,通常咱们在服务端这么作就能够了Access-Control-Allow-Origin: *。
那么咱们如今回到JWT的主题上。
咱们先来看一段jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
仔细观察咱们能够发现这一段字符串中含有两个 " . ",这两个 " . "把jwt分红了三份,咱们分别成为头部、荷载信息、签证信息。那么这三部分的分工是什么呢?
JWT的头部承载了两个信息
完整的头部应该是像这样的一个Json
{ 'typ': 'JWT', 'alg': 'HS256' }
将头部Json进行base64加密就获得了咱们的第一部分
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
第二部分是荷载信息,Payload,你能够理解为咱们的JWT是一辆大仓库,第一部分头部就是仓库的名称编号等基础信息,而荷载信息就是仓库的自己,包含了仓库里面的全部货物。这些信息又包含了三个部分:
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过时时间,这个过时时间必需要大于签发时间
nbf: 定义在什么时间以前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的惟一身份标识,主要用来做为一次性token,从而回避重放攻击。
公共的声明能够添加任何的信息,通常添加用户的相关信息或其余业务须要的必要息。但不建议添加敏感信息,由于该部分在客户端可解密。
私有声明是提供者和消费者所共同定义的声明,通常不建议存放敏感信息,由于base64是对称解密的,意味着该部分信息能够归类为明文信息。
事实上咱们的Header和Payload都是基于base64加密的,这种密文都是能够对称解密的,所以请不要存放敏感信息。
定义一个payload:
{ "sub": "1234567890", "name": "John Doe", "admin": true }
进行base64加密后,获得了咱们的第二部分
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
Jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
这一部分能够理解为对前部分的一个校验,将前两部分加密后的密文经过在Header中定义的加密方式,与服务端所传入的密钥进行一次加密,假如前两部分的信息被篡改的话,必然通不过最后一部分签证的校验。所以经过这样保证了Jwt的安全性。
所以,保存并隐藏好咱们的加密密钥是很是重要的,假设泄露了,就意味着任何知道密钥的人均可以轻松的对jwt进行自我签发和验证。
若是个人文章帮到了你,请帮忙点个赞,点个关注。谢谢!