Appearance
1.http 无状态
不论是 cookie、session、token 都是用来校验用户身份的令牌,但为什么会出现令牌??因为 HTTP 是无状态的协议,上一次请求和下一次请求无任何关系、无上下文。Web 应用想要知道用户的登录态就需要使用令牌了,通过令牌可以识别用户身份,从而操作对应用户的数据。
在客户端发送登录请求后,服务端校验后给客户端颁发令牌,客户端下次发送请求服务端就可以鉴别请求的用户了。
2.cookie(客户端存储)
cookie 是 HTTP 头部的字段,同时 cookie 也可以专门保存在本地浏览器中。在登录成功后,服务端在响应头部中设置 cookie,cookie 数据中一般包含识别用户身份的信息,客户端接收到后会将 cookie 存储起来,下次发送请求浏览器会自动在请求头部中携带 cookie,校验以及识别用户身份。
浏览器本地的 cookie 是可以通过 JS 随意添加的,所以 cookie 可以被伪造。服务端可以设置字段 HTTP Only 禁止 JS 随意修改某个 cookie 字段。
3.session(服务端存储)
session 的出现是为了解决 cookie 会被伪造的问题。
所有的用户令牌由服务端维护,通过一个 key:value 的映射表来记录用户登录态,在客户端登录成功时,服务端创建 key:value(例如:"随机字符串":"张三")的一条记录,给客户端返回这个key
,通过设置响应头部中设置 cookie 即可。客户端将cookie
保存,下一次发送请求携带上key
,服务端匹配查询是否有这个key
,有则说明合法,无则说明不合法,合法通过读取这个key
的value
来识别这个用户。
可以有效避免 cookie 被伪造,既时客户端修改了 key,服务端是无法命中映射表的。
但是session
的问题是:如果存在多个服务器如负载均衡时,每个服务器的状态表必须同步,或者抽离出来统一管理,如使用Redis
等服务。
4.token
session
方案对服务端的开销是比较大的,需要维护用户登录态。而 token 方案采用了客户端存储+加密,服务端检验来识别用户身份的。
例如 JWT 就是使用 token 方案的。JWT
由 3 部分构成:头部,负载和签名,加密方式采用对称加密。
- 头部存储
Token
的类型和签名算法(上图中,类型是jwt
,加密算法是HS256
) - 负载是
Token
要存储的信息(上图中,存储了用户姓名和昵称信息) - 签名是由指定的算法,将转义后的头部和负载,加上密钥一同加密得到的。
最后将这三部分用.
号连接,就可以得到了一个Token
了。
客户端如何存储token
呢?
- 存在
cookie
中,虽然设置HttpOnly
可以有效防止XSS
攻击中token
被窃取,但是也就意味着客户端无法获取token
来设置CORS
头部。 - 存在
sessionStorage
或者localStorage
中,可以设置头部解决跨域资源共享问题,同时也可以防止CSRF
,但是就需要考虑XSS
的问题防止凭证泄露。