在之前的一篇文章中,简单谈了一下基于token的身份校验。不够完整,还有一些错误的地方,这里再谈谈。
1 移动端的token
从实际场景看,很多时候,移动端对后端服务器的访问不是从内嵌浏览器中发出的,而是在代码中直接发出一个HTTP请求。对于某些APP来说,可能使用很久才会请求一次服务器。这时再采用Cookie来存储token就不太合适了。服务器可以直接在响应结果中返回token,客户端将token存储在本地,将来发送请求时再带上。没有Cookie也就可以避免CSRF攻击了,但客户端同样需要小心保存token。
2 token的生成
+ +
| |
+--------+ | | +-----------------------+
| | | (1) login(username, pasword) | | |
| client | | | | server |
| | | ------------------------------------> | | |
| | | | | |
| | | | | |
| | | (2.1) validate(username, password) | | |
| | | (2.2) generateAccessToken(userId) | | |
| | | | | |
| | | <-----------------------------------+ | | |
| | | | | |
| | | | | |
| | | (3)requestToURI(userId, accessToken) | | |
| | | | | |
| | | ------------------------------------> | | |
| | | | | |
+--------+ | | +-----------------------+
+ +
使用JWT(JSON Web Token),在token中附带上相关信息,使token自身具有了时效性、指向性和保密性。
JWT中自带了几个默认的属性:
- iss (Issuer): token颁发者
- sub (Subject): token主题
- aud (Audience): token接受者
- **exp (Expiration Time): token的超时时间
- **nbf (Not Before): token的起效时间
- **iat (Issued At): token的颁发时间
-
**jti (JWT ID): token的唯一标识
- 时效性:JWT中包含了当前token的失效时间和起效时间,应用服务器可以根据相应的时间来判断该token是否有效
- 指向性:JWT中包含了当前token的颁发者和审计信息,应用服务器可以根据相应的信息来判断当前token与当前用户是否相匹配
- 保密性:JWT中包含了签名字段,该字段是由服务器加密生成的(对称或非对称皆可),应用服务器可以校验该签名来判断当前token是否是伪造的
当然,仅靠token自身数据是不足以保证安全性的,还需要后端服务器的配合才行。后端服务器需要判断该token是否已经被废弃掉了。
3 token安全性
由于客户端通过token来标明自身身份,对于服务器来说,就相当于客户端的密码。服务器端在存储该token时,也需要认真对待。
- 不可直接存储该token,应对token做散列处理(例如使用Bcrypt做散列)
- 服务器需要将接收到token和自己的保存的token作比较,防止用户使用已废弃但还未过期的token
4 其他
上面所说的token并不支持用户在多个设备上同时登陆,即每个用户只能有一个token。当用户需要同时在多个设备上保持登陆状态时,就需要针对不同的设备生成不同的token。由于移动设备的IP经常换,因此就需要使用一些其他可以标识设备的属性来确定token的唯一性。