http 是无状态,也就是说每次的http请求都是独立的。请求和响应无法维护,都是一次性的,
比说 在blog 上留言 发布都需要用户信息的,我们要存储登录用户的状态,
**存储方式**
1.最low 的方法 在window 上挂载用户信息,但是刷新页面 状态就丢失了。
2.放在cookie ,localstorge等里,无论怎么刷新,用户信息都可以持久保留
### cookie
对于前端来说是无感知的,首次请求server返回Set-Cookie:'name=123\&age=333',下次cilent请求自动回带上Cookie 信息
cookie 配置
* Domain / Path
Domain 域 限制访问域
假如server 返回cookie 中携带Domian baidu.com,与当前域名不符,browser 会拒绝存储cookie,反之与当前域名相同 浏览器会存储, server 没有指定Domain 默认存储当前一级域名
Path 访问路径
server 返回 path /ace browser 只有在 /ace/?\* 接口上传输cookie
path / 所有接口都会传输cookie,前提是域名一致
* Expires / Max-Age
Expires UTC 格式 过期时间 为空情况 当浏览器关闭,cookie就会消失,会与本地时间做对比,不是很准确
Max-Age 从当前时间到过期时间的秒数,时间过期,browser 不在存储cookie,Expires 和Max—Age 同时存在,Max-Age 优先级更高,如果都没有设置,那么cookie 将在会话结束就清空了
* httponly 不允许client 获取cookie
每次请求都会携带Cookie,这无形中增加了流量开销。
Http请求中Cookie均为明文传输,所以安全性成问题(除非用Https)
Cookie有大小限制,一般最大为4kb。
**cookie 跨源携带**
client 在5500 port
serve 在8000 port
默认情况下,浏览器是不会去为你保存下跨域请求响应的Cookie的。具体现象是:跨域请求的Response响应了即使有Set-Cookie响应头(且有值),浏览器收到后也是不会保存此cookie的。
首先服务端设置cors请求头 并开启Access-Control-Allow-Credentials 允许在跨域情况setCookie
client 设置withCredentials = true 需要在跨域情况存储cookie
注意开启Access-Control-Allow-Credentials,Access-Control-Allow-Origin就不可以设置为\* 了,报错如下。 必须指定host 也就是指定为<http://localhost:5500>
Access to XMLHttpRequest at 'http://localhost:8000/login' from origin 'http://localhost:5500' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
const host = 'http://localhost:5500';
// 设置请求头
app.all('*', function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', host);
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader("Content-Type", "application/json;charset=utf-8");
next();
});
document.getElementById('login').onclick = () => {
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数
ajax.open('get', 'http://localhost:8000/login');
<!--关键 开启withCredentials-->
ajax.withCredentials = true;
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
console.log(ajax.responseText); //输入相应的内容
}
};
};
这样就可以跨域携带cookie 了
### session
session 一般用在 前后鉴权 登录/验证
* 浏览器登录发送账号密码,服务端查用户库,校验用户
* 服务端把用户登录状态存为 Session,生成一个 sessionId
* 通过登录接口返回,把 sessionId set 到 cookie 上
* 此后浏览器再请求业务接口,sessionId 随 cookie 带上
* 服务端查 sessionId 校验 session
* 成功后正常做业务处理,返回结果
session 存储是一个问题
在内存中存储,用户量级过大,可能导致内存溢出 吃满,如果server 是集群,每次服务器资源都是独立的 不会共享,负载均衡 每次可能会把流量打到不同服务器上,session就会失去作用,解法通过nginx配置 把相同ip流量打到一个服务器上 也可以,通过ip\_hash配置 但是就失去了负载均衡作用
在redis 存储 访问快 而且数据共享,但是内存有限(最优)
在数据坤中存储 空间大,但是访问速度慢
### token
由于session 存储限制,就产生了token,不在服务端存储session了,生成token 后 通过cookie 返回给client 每次请求携带token server 去效验token 信息
**使用token 流程**
* 用户登录,服务端校验账号密码,获得用户信息
* 把用户信息、token 配置编码成 token,通过 cookie set 到浏览器
* 此后用户请求业务接口,通过 cookie 携带 token
* 接口校验 token 有效性,进行正常业务接口处理
token 放在cookie 里传输,明文铁定是不可以的,一般使用base64 加密一下,这也是不安全的。用户a拿到b的uid在转为base64,在修改自己的token,这样不就能登录b的账户了吗
token 设计到敏感操作,所以 需要加密签名sign
#### JWT
JWT是由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。
`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ`
```
header 头部信息
// 加密算法 方式
// {
// 'typ': 'JWT',
// 'alg': 'HS256'
// }
// 在base64 加密 生成下面一坨东西
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
中间部分 payload 负载
由自定义信息 (不建议存放敏感信息,因为是对称加密,client是可以解密的)通过base64 加密
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
signtrue 签证信息
有heaher base64后信息和payload base64后信息加上header内加密方法配合secret (秘钥)加密生成signtrue信息
secret 保存在服务器中, header 和payload 都可以破解,但是没有secret 破解也没有用, secret 用作于jwt 的签发 和jwt 的效验
```