JWT
-
官方文档:https://jwt.io/introduction
-
简介:JWT是一种开放标准(RFC 7519) ,它定义了一种紧凑和自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。可以验证和信任此信息,因为它是数字签名的。JWT签名(Signature)可以使用 secret (使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
-
JWT结构:三大部分字符串,header和payload串是Json对象通过Base64 URL算法加密生成,字符之间通过"."分隔符分为三个子串,所以JWT的有效格式为:
Header.Payload.Signature
-
Header(头部)
-
通常由两部分组成: 令牌的类型(即 JWT)和所使用的签名算法(如 HMAC SHA256或 RSA)。如:
{ "alg": "HS256", "typ": "JWT" }
-
-
Payload(有效负载)
- JWT的主体内容部分,它包含三部分声明(要求)。声明是关于实体(通常是用户)和其他数据的声明,本质上保存有用户数据(如userID)
- 标准中注册的声明
- JWT 规定了7个官方字段,供选用,建议但不强制使用,详细见官方文档
- 公共的声明
- 公共的声明可以添加任何的信息,可以随意定义。一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.(一般不定义该声明)
- 为了避免冲突,它们应该在 IANA JSON Web Token Registry 中定义,或者定义为包含抗冲突名称空间的 URI
- 公共的声明可以添加任何的信息,可以随意定义。一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.(一般不定义该声明)
- 私有的声明
- 私有声明是提供者和消费者所共同定义的共享信息声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
- 标准中注册的声明
- JWT的主体内容部分,它包含三部分声明(要求)。声明是关于实体(通常是用户)和其他数据的声明,本质上保存有用户数据(如userID)
-
Signature(签名)
-
这个签名信息由三部分组成:
- header (base64后的)
- payload (base64后的)
- secret
这个部分需要base64加密后的header和base64加密后的payload使用
.
连接组成的字符串,然后通过header中声明的加密方式进行加盐secret
组合加密,然后就构成了jwt的第三部分
-
- 注意:
- secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
- JWT真正目的不在加密保护数据,而是为了认证来源,认证来源,认证来源。JWT不保证数据不泄露,因为JWT的设计目的就不是数据加密和保护。
-
-
Base64URL
-
这个算法跟 Base64 算法基本类似,但有一些小的不同。
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符
+
、/
和=
,在 URL 里面有特殊含义,所以要被替换掉:=
被省略、+
替换成-
,/
替换成_
。这就是 Base64URL 算法。
-
-
JWT用途
-
信息存储交换,用于认证来源
- 使用 JWT,可以降低服务器查询数据库的次数
- 使用JWT,可以降低服务器请求其他其他三方服务器的次数
-
身份认证授权
-
认证原理
这个图中有三个主体: user, application server和authentication server
非常常见的一个架构:
-
首先用户需要 通过登录等手段向authentication server发送一个认证请求,authentication会返回给用户一个JWT,将其存储在Cookie或localStorage中。
-
此后用户向application server发送的所有请求都要捎带上这个JWT,然后application server会验证这个JWT的合法性,验证通过则说明用户请求时来自合法守信的客户端。
-
通用流程:浏览器第一次访问服务器,根据传过来的唯一标识userId,服务端会通过一些算法,如常用的HMAC-SHA256算法,然后加一个密钥,生成一个token,然后通过BASE64编码一下之后将这个token发送给客户端;客户端将token保存起来,下次请求时,带着token,服务器收到请求后,然后会用相同的算法和密钥去验证token,如果通过,执行业务操作,不通过,返回不通过信息。
-
如何捎带:
-
把它放在 Cookie 里面自动发送,但是这样不能跨域
-
放在 HTTP 请求的头信息
Authorization
字段里面:Authorization: Bearer <token>
//前端api举例 fetch('api/user/1', { headers: { 'Authorization': 'Bearer ' + token } })
-
该方法流程:
-
-
跨域的时候,JWT 就放在 POST 请求的数据体里面
-
-
-
-
可实现场景
-
跨域身份验证
-
跨域问题:
互联网服务离不开用户认证。一般流程是下面这样。
1、用户向服务器发送用户名和密码。
2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3、服务器向用户返回一个 session_id,写入用户的 Cookie。
4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。
这种模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。
举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现?
-
三类解决方法
-
使用Nginx中的ip绑定策略,同一个ip只能在指定的同一个机器访问(不支持负载均衡)
-
session管理:
-
session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。
- 使用数据库同步session(效率不高)
- 使用Spring-Session+Redis实现(保留session最常用的方案)
- 以下为两者结合示意图
-
session复制同步:使用tomcat内置的session同步(同步可能会产生延迟)
-
-
服务器索性不保存 session 数据了,所需数据都保存在客户端,每次请求都发回服务器。
- 使用cookie来完成,cookie保存原session序列化加密信息(很明显这种不安全的操作并不可靠)
- 使用token代替session,JWT 就是这种方案的一个代表,以下为示意图。
- 三类具体说明或实现见下方
什么是session及跨域session解决
指定的链接
-
-
与session登录区别
- 什么是session及跨域session解决:https://www.cnblogs.com/jing99/p/11785070.html
- 着重查看session最常用的解决和应用:Spring-session及Redis存储
- 里面涉及token请忽略,查看下方
什么是Token
更详细介绍
- 什么是Token:https://www.cnblogs.com/lightzone/p/9749076.html,(
Json Web Token长什么样子呢?
后就无需查看,上文已经介绍过,着重查看优点) - session和token区别:
- https://blog.csdn.net/mydistance/article/details/84545768
- https://zhuanlan.zhihu.com/p/86937325
- 着重查看5.2-5.4
- 什么是session及跨域session解决:https://www.cnblogs.com/jing99/p/11785070.html
-
-
单点登录
- https://www.jianshu.com/p/613e44d4a464
- 上述四种方式中,第一种方式:
以Cookie作为凭证媒介
包括了常用的OAuth2和JWT实现 - 第四种:
使用独立登录系统
:其用户中心验证通常都是采用第一种方式进行验证
-
-
OAuth2和JWT的区别
- oauth2有client和scope的概念,jwt没有。如果只是拿来用于颁布token的话,二者没区别。常用的bearer算法oauth、jwt都可以用。应用场景不同而已
- Spring Cloud 的权限框架就是用的jwt实现的oauth2 。二者没有必然联系
- Token功能不一样,JWT的token是包含用户基本信息的,然后通过加密的方式生成的字符串,服务器端拿到这个token之后不需要再去查询用户基本信息,解析完token之后就能拿到。想想在微服务架构下,用户服务是一个单独的服务,但是其他服务大部分情况下也会需要用户信息,难道要每次用到都去取一次吗? JWT非常适合微服务。
- OAuth2用在使用第三方账号登录的情况(比如使用weibo, qq, github登录某个app)。OAuth2是一个相对复杂的协议, 有4种授权模式, 其中的access code模式在实现时可以使用jwt才生成code, 也可以不用. 它们之间没有必然的联系.
- JWT是用在前后端分离, 需要简单的对后台API进行保护时使用.(前后端分离无session, 频繁传用户密码不安全)
- JWT是一种认证协议 。JWT提供了一种用于**发布接入令牌(Access Token),**并对发布的签名接入令牌进行验证的方法。 令牌(Token)本身包含了一系列声明,应用程序可以根据这些声明限制用户对资源的访问。
- OAuth2是一种授权框架。提供了一套详细的授权机制(指导)。用户或应用可以通过公开的或私有的设置,授权第三方应用访问特定资源。
- 总结:
- Oauth2和jwt是完全不同的两种东西,一个是授权认证的框架,另一种则是认证验证的方式方法(轻量级概念)。
- OAuth2不像JWT一样是一个严格的标准协议,因此在实施过程中更容易出错。尽管有很多现有的库,但是每个库的成熟度也不尽相同,同样很容易引入各种错误。在常用的库中也很容易发现一些安全漏洞。
- OAuth2常用在使用第三方账号登录的情况(比如使用weibo, qq, github登录某个app),而JWT是常用在前后端分离, 需要简单的对后台API进行保护时使用
-
JWT缺点
- JWT 默认是不加密,故JWT 不加密的情况下,不能将秘密数据写入 JWT。
- 解决:可再加密:生成原始 Token 以后,可以用密钥再加密一次。
- JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。(再其他博客有查看到一个token撤销概念:
它允许我们根据相同的授权许可使特定的token甚至一组token无效
。在这里就存在冲突)
- JWT 默认是不加密,故JWT 不加密的情况下,不能将秘密数据写入 JWT。
-
JWT安全保证
-
为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
-
JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
-
请求时token过期自动刷新token?
当token失效时,现在的网站一般会做两种处理方法:
- 跳转到登陆页面,让用户重新登陆获取新的token(OAuth中不包含Refer-Token的方式)
- 当检测到请求失效时,网站自动去请求新的token(OAuth中使用Refer-Token的方式去请求,在app保持登陆状态上面用得比较多)
-
-
-
-