jwt
https://www.easyswoole.com/Components/jwt.html
https://baijiahao.baidu.com/s?id=1608021814182894637&wfr=spider&for=pc
使用 JWT 实现单点登录(完全跨域方案)
JWT:JSON Web Token
JWT 不仅可用于认证,还可用于信息交换。善用 JWT 有助于减少服务器请求数据库的次数
生成 token 编码
将 用户信息 + 固定数据(加密方式、用户、过期时间等)+ 密钥 加密,得到 签名,然后将这四部分数据 base64 编码,生成一个长字符串,这个长字符串就是 token
注意:
- 密钥保存在服务器上,千万不能泄露,可以设置成 项目名称+随机字符串 的格式
- token 中的所有信息都是公开的,所以一定不能存放密码等隐私信息
- 一旦 JWT 签发,有效期内将会一直有效,不能取消 token 或更改 token 的权限为了减少盗用,JWT 的有效期不宜设置太长。对于某些重要操作,用户在使用时应该每次都进行进行身份验证
- 密钥可以保证 token 的安全性,但是无法防止 token 的盗用问题,为了减少盗用和窃取,推荐使用 HTTPS 协议进行传输
解析 token 解码
base64 解码 token,得到一堆明文信息和签名,明文信息里有一个字段说明了加密用的算法,将明文信息使用指定的加密方式加密,如果等于签名,则 token 校验通过,在进行超时等其他参数的校验
easyswoole 中的 jwt
官方文档:https://www.easyswoole.com/Components/jwt.html
官方文档写的比较简略,通过查阅源码,可以有更详细的了解。
token 由三或四部分组成:
前缀:prefix,可省略
头部:header,是 alg(加密方式)和 typ(类型,默认 JWT 且无法更改)的组合,经过 base64 转码
有效载荷:payload,包含以下信息,经过 base64 转码
1
2
3
4
5
6
7
8
9
10
11'exp' => $this->getExp(), // 过期时间,默认两个小时
'sub' => $this->getSub(), // 主题,没有默认值
'nbf' => $this->getNbf(), // 在此之前不可用,默认time()
'aud' => $this->getAud(), // 用户,无默认值
'iat' => $this->getIat(), // 发布时间,默认time()
'jti' => $this->getJti(), // jwt-id,用于标识jwt,默认10字节的随机字符串
'iss' => $this->getIss(), // 发行人,默认'EasySwoole'
// token状态,0初始状态,1合法token,-1非法token,-2过期token,生成token的时候,status默认给1
// 不太理解payload中为什么要包含这个字段
'status' => $this->getStatus(),
'data' => $this->getData() // 自定义的数据必要的信息都有默认值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// Jwt
private $secretKey = 'EasySwoole';
private $alg = Jwt::ALG_METHOD_HS256; // 默认加密方式
// JwtObject
protected $iss = 'EasySwoole'; // 发行人
if (empty($this->nbf)) {
$this->nbf = time();
}
if (empty($this->iat)) {
$this->iat = time();
}
if (empty($this->exp)) {
$this->exp = time() + 7200;
}
if (empty($this->jti)) {
$this->jti = Random::character(10);
}签名:signature,包含 secretKey(秘钥)、header、payload、alg,经过加密然后 base64 转码
除了 secretKey,其他所有信息相当于都是明文,secretKey 储存在服务器的内存中,如果重启服务,secretKey 就会丢失,之前的 token 就都无法通过校验,所以推荐直接修改 Jwt 组件中的默认 secretKey,然后在生成 token 的时候,不指定 secretKey,使用默认值
生成 token,以下是最简略的写法:
1 | use EasySwoole\Jwt\Jwt; |
生成 token,以下是推荐写法:
1 | use EasySwoole\Jwt\Jwt; |
自动续期
设置 token 过期时间 2h,2h 内用户一直在操作,然后贸然过期肯定不合理,所以 token 要有自动续期机制。
方案:
- 后端:每次校验 token 的过期时间,如果过期但是过期时间不超过 4 个小时,则生成一个新 token,并附着在此次请求返回的数据的基础上。这里用“refreshToken”字段
- 前端:每次 http 请求校验返回值中有没有“refreshToken”字段,如果有,则刷新本地 token