JWT,在HTTP通信过程中,进行身份认证。它是一种开放标准,一种规范化之后的 JSON 结构的 Token。JWT 自身包含了身份验证所需要的所有信息,因此我们的服务器不需要存储 Session 信息。增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
对比Session和JWT实现认证授权
首先我们要知道什么是授权。授权就是获得一定的权限后,才能进行某些操作。
假设我们现在在逛某宝,然后想要查看自己的购物车,那么这时候服务器肯定会对我们进行判断,只有我们登录了才能查看自己的购物车。这个登录的过程就可以理解为对我们进行授权的过程。
先看看如何通过Session进行授权的:
再看看JWT是如何进行授权的:
对比之下我们可以发现,JWT是不用在服务器保存用户的登录信息(Session)的,只用对Token进行验证, 验证成功后返回客户端希望得到的数据就可以了。
JWT是一个很长的字符串,中间用点(.)分隔成三个部分,分别是Header(头部)、Payload(负载)、Signature(签名)。JWT内部是没有换行的,并且都使用Base64编码。
1.Header
Header
部分是一个JSON对象,描述JWT最基本的信息,例如Token
类型及签名所用的算法等。表示如下:
{
"alg": "HS256",
"typ": "JWT"
}
alg属性
表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);
typ属性
表示这个令牌(token)的类型(type),JWT令牌统一写为JWT。
最后,将上面的JSON对象使用Base64URL
算法转成字符串。
2.Payload
Payload
部分也是一个JSON对象也是使用Base64URL
算法转成的字符串,用来存放实际需要传递的数据。JWT规定了7个官方字段,供选用。
iss (issuer)
:该JWT的签发者
exp (expiration time)
:过期时间(为一个UNIX时间戳)
sub (subject)
:该JWT所面向的用户
aud (audience)
:接受该JWT的一方
nbf (Not Before)
:生效时间
iat (Issued At)
:签发时间
jti (JWT ID)
:编号
{
"iss": "John Wu JWT",
"iat": 1441593502,
"exp": 1441594722,
"aud": "www.example.com",
"sub": "jrocket@example.com",
"from_user": "B",
"target_user": "A"
}
Payload 部分默认是不加密的,一定不要将隐私信息存放在 Payload 当中!
3.Signature
Signature 部分是对前两部分的签名,作用是防止 JWT(主要是 payload) 被篡改。
这个签名的生成需要用到:
签名计算公式如下:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.
)分隔,这个字符串就是 JWT 。
JWT是如何进行校验的
服务端拿到 JWT 之后,会解析出其中包含的 Header、Payload 以及 Signature 。服务端会根据 Header、Payload、密钥再次生成一个 Signature。拿新生成的 Signature 和 JWT 中的 Signature 作对比,如果一样就说明 Header 和 Payload 没有被修改。
所以密钥
是很重要的,密钥
决定了签名
,签名
决定了JWT的安全性
。
(1)JWT默认是不加密,但也是可以加密的。生成原始Token以后,可以用密钥再加密一次。
(2)JWT不加密的情况下,不能将重要数据写入JWT。
(3)JWT不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
(4)JWT的最大缺点是,由于服务器不保存session状态,因此无法在使用过程中废止某个token,或者更改token的权限。也就是说,一旦JWT签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
(5)JWT本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用HTTPS
协议传输。
(7)便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的
(8)它不需要在服务端保存会话信息,所以它易于应用的扩展
1.单点登录
在有多个系统的情况下,我们在A系统登录了,如何让B系统也感知到我们已经登录?
通过JWT的Token,用户访问不同的系统时,只需要从Cookie中取出Token,将Token进行验证一下就可以了。
不过这样还有一个问题,Cookie是不能跨域的。
比如说,我们请求
时,浏览器会自动把google.com
的Cookie带过去给google
的服务器,而不会把
的Cookie带过去给google
的服务器。
这就意味着,由于域名不同,用户向系统A登录后,系统A返回给浏览器的Cookie,用户再请求系统B的时候不会将系统A的Cookie带过去。
关于跨域问题
跨域的根本原因就是因为浏览器的同源策略,这是浏览器出于安全性考虑做出的限制,所谓同源是指:域名、协议、端口相同。
比如在互联网上有两个资源(网页或者请求等),如果A想要访问B的资源,如果A、B并非同源,即域名、协议、端口有任意一个不相同,那么就会出现跨域问题。
为了解决Cookie的跨域问题,我们可以采取以下几种方法:
例如:www.taobao.com、nv.taobao.com、nz.taobao.com、login.taobao.com
Set-Cookie: jwt=lll.zzz.xxx; HttpOnly; max-age=980000; domain=.taobao.com
注意domain必须设置为一个点加顶级域名,即.taobao.com。这样,taobao.com和*.taobao.com就都可以接受到这个Cookie,并获取JWT了。
2.解决CSRF问题
CSRF,也叫跨站请求伪造,攻击者通过盗用你的身份,以你的名义发送恶意请求。
JWT是如何防止CSRF呢?
CSRF是依靠盗用用户的Cookie来得到用户身份,实现发送请求。为了防止Cookie被盗用,我们可以将JWT的Token存放在SessionStorage
或者LocalStorage
中,发送请求时将Token放在请求头中。这样不依赖Cookie,自然也就无法进行CSRF攻击了。
web本地存储:SessionStorage和LocalStorage
- sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。
- localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。