OAuth协议中说到的AccessToken可以是以下两种:
1.任意只起到标识作用的字符串:这种情况下Resource Server处理请求时需要去找Authorization Server获取用户信息。
2.携带用户基本信息的加密字符串:这种情况下Resource Server处理请求时只需解析AccessToken,直接获取到用户信息即可。
JWT就是用来生成第二种access token的一种协议。具体介绍:JWT
具体来说,一个JWT token就是如下一串字符串:
这个字符串由3部分(Header, Payload, Signature)组成,用"."分隔。
Header
这一部分时用来定义构造JWT的参数信息,用一个JSON对象表示如下:
{ "alg": "HS256",//定义JWT中的Signature所用的算法 "typ": "JWT"//表示Token的类型,此处统一写成JWT }
将上述JSON对象的字符串形式进行Base64Url编码之后就得到了token中的header部分。
Payload
这一部分是存储业务信息的地方。信息也以JSON对象的方式表示:
{ "iss": "Jensen",//签发人 "exp": "1308726283"//token过期时间戳 }
对象中的key其实可以为任意字符串。但是为了让token字符串尽可能小。key尽量统一为3各字符。然后为了将一些常用的key标准化,JWT定义了如下标准key:
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
详见 RFC7519
当然我们也可以定义自己的key,比如:name:姓名,admin:是否为admin...
将上述JSON对象的字符串形式进行Base64Url编码之后就得到了token中的payload部分。
Signature
将header和payload部分的base64字符串用特定的密钥进行hash得到签名部分。比如我们选用HMAC SHA256
作为签名算法,则签名过程如下:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
secret
只有服务器端才知道,通过签名可以防止token被修改。
与OAuth验证结合
采用这种方式生成的access token, Resouce Server处理请求的时候(access token可以放在Authorization Header中,比如:Bearer xxxx)可以直接解析。但是这里有
两个问题:
1. Authorization Server和Resource Server如何共享签名的secret?
最简单的方法就是Resource Server和Authorization Server使用统一的secret。但是这样的话如果有很多Resource Server(比如不同的资源提供者)共用一个Authorization
Server的话可能就有安全问题,这种情况下就需要针对不同的resource server使用不同的secret进行签名了。同时client在申请token的时候也需要告知要访问那个resource server。
2. Token的失效问题
因为Token是在Resource Server直接解析,意味着一旦签发,在其到期前一直有效。用户logout后也没办法将已经产生的token设置为无效。
要解决这个问题,还是需要Resource Server将access token提交至Authorization Server验证。Authorization Server可以将access token进行缓存或者
缓存采用相关算法为其生成的key(比如用签名作为key),验证时只需验证key是否存在即可。(当然,我们我进行失效处理时可以把缓存的key删掉即可)