除了向服务器发起请求验证token是否过期以外,一些类型的token是直接将过期时间储存在token之中的,我们可以通过这一点在客户端本地验证token是否过期。
token的构成
token其实就是三个东西以小数点分隔开的字符串
例如:
1
| eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuYXV0aDAuY29tLyIsImF1ZCI6Imh0dHBzOi8vYXBpLmV4YW1wbGUuY29tL2NhbGFuZGFyL3YxLyIsInN1YiI6InVzcl8xMjMiLCJpYXQiOjE0NTg3ODU3OTYsImV4cCI6MTQ1ODg3MjE5Nn0.CA7eaHjIHz5NxeIJoFK9krqaeZrPLwmMmgI_XiQiIkQ
|
你可以在上面的token中发现两个小数点,而被这两个小数点分隔的部分分别是:
1
| Header的base64.Payload的base64.Signature
|
- Header中声明了token的元数据,例如使用的加密算法类型和token的类型
- Payload中包含了实际的数据,例如用户名等,这部分的信息内容可由后端开发人员自由调整
- Signature确保 JWT 未被篡改,如果 JWT 由服务器签发,服务器会用 secret 生成签名,客户端无法伪造
你其实可以随便在网上搜一个base64解码器,然后删除Signature部分进行解码,例如上述token删除Signature部分解码后的结果是:
1
| {"alg":"HS256","typ":"JWT"}{"iss":"https://example.auth0.com/","aud":"https://api.example.com/calandar/v1/","sub":"usr_123","iat":1458785796,"exp":1458872196}
|
在本地检测token是否过期
在上述token拥有的数据中,payload部分的exp
字段是一个时间戳,指定了该token的过期时间
时间戳就是从1970年1月1日至今以来的秒数或毫秒数,如果时间戳是10位,那么就是秒数,13位就是毫秒数,上面的例子中,使用的是秒级时间戳
通过exp
字段,我们就能判断token什么时候过期,从而决定是否该使用refreshToken来刷新accessToken
我们可以实现一个方法来判断token是否过期(使用Dart实现,其他语言大同小异):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| bool isTokenExpired(String token){ try{ final List<String> parts = token.split("."); if(parts.length != 3){ throw Exception("Invalid Token"); } final payloadString = utf8.decode(base64Url.decode(base64Url.normalize(parts[1]))); final Map<String, dynamic> payloadMap = json.decode(payloadString); if(!payloadMap.containsKey("exp")){ throw Exception("Token doesn't have expiry date"); } final currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000; if(currentTime < payloadMap['exp']){ return false; } else{ return true; } } catch(e){ debugPrint("$e"); return true; } }
|