首先思考一个问题,为什么会出现cookie?
假设一个新闻网站,服务器有一个接口,通过请求这个接口,可以添加发布一篇文章。但是,不是任何人都有权力做这种操作的
服务器如何知道请求接口的人是有权力的呢?只有登录过的管理员才能做这种操作
问题是,客户端和服务器的传输使用的是http协议,http协议是无状态的,什么叫无状态,就是服务器不知道这一次请求的人,跟之前登录请求成功的人是不是同一个人。由于http协议的无状态,服务器忘记了之前的所有请求,它无法确定这一次请求的客户端,就是之前登录成功的那个客户端。
于是,服务器想了一个办法
它按照下面的流程来认证客户端的身份
- 客户端登录成功后,服务器会给客户端一个出入证(令牌 token)
- 后续客户端的每次请求,都必须要附带这个出入证(令牌 token)
服务器发扬了认证不认人的优良传统,就可以很轻松的识别身份了。
但是,用户不可能只在一个网站登录,于是客户端会收到来自各个网站的出入证,因此,就要求客户端要有一个类似于卡包的东西,储存各种token,这个小卡包就是cookie
1.cookie的组成
cookie是浏览器中特有的一个概念,它就像浏览器的专属卡包,管理着各个网站的身份信息。
每个cookie就相当于是属于某个网站的一个卡片,它记录了下面的信息:
- key:键
- value:值
- domain:域,表达这个cookie是属于哪个网站的
- path:路径,表达这个cookie是属于该网站的哪个基路径的,就好比是同一家公司不同部门会颁发不同的出入证。比如
/news
,表示这个cookie属于/news
这个路径的。 - secure:是否使用安全传输
- expire:过期时间,表示该cookie在什么时候过期
当浏览器向服务器发送一个请求的时候,它会瞄一眼自己的卡包,看看哪些卡片适合附带捎给服务器
如果一个cookie同时满足以下条件,则这个cookie会被附带到请求中
- cookie没有过期
- cookie中的域和这次请求的域是匹配的- 比如cookie中的域是
baidu.com
,则可以匹配的请求域是baidu.com
、www.baidu.com
、blogs.baidu.com
等等- 比如cookie中的域是www.baidu.com
,则只能匹配www.baidu.com
这样的请求域- cookie是不在乎端口的,只要域匹配即可 - cookie中的path和这次请求的path是匹配的- 比如cookie中的path是
/news
,则可以匹配的请求路径可以是/news
、/news/detail
、/news/a/b/c
等等,但不能匹配/blogs
- 如果cookie的path是/
,可以想象,能够匹配所有的路径 - 验证cookie的安全传输- 如果cookie的secure属性是true,则请求协议必须是
https
,否则不会发送该cookie- 如果cookie的secure属性是false,则请求协议可以是http
,也可以是https
如果一个cookie满足了上述的所有条件,则浏览器会把它自动加入到这次请求中
具体加入的方式是,浏览器会将符合条件的cookie,自动放置到请求头中
cookie中包含了重要的身份信息,所以cookie一般都会加密
二.服务器设置cookie
这里以登录为例,用到了cookie-parser插件来设置cookie
//如果登录成功,在响应头中设置cookie
// res.header("set-cookie", `token=${req2.id};path ="/";domain = localhost;max-age = 3600,`)
//登录成功设置cookie
let value = adminObj[i].user;
console.log(value);
//这里的cookie属性是 加入cookie-parser中间件之后带来的属性
res.cookie("token", value, {
path: "/",
domain: "localhost",
maxAge: 7 * 24 * 3600 * 1000, //毫秒
signed: true
})
// 针对其他终端设备,遵守开发者约定
res.header("authorization", value)
三.服务器判断前端是否携带cookie
这里以登录为例,如果没有登录则没有cookie,则不让进入主页
下面是封装的cookie判断的中间件
//token 的加密和验证
//认证
//对需要认证的端口进行限制
const { pathToRegexp } = require("path-to-regexp");
// 需要登录认证后才可以访问的接口
const needTokenApi = [
{ method: "POST", path: "/html/main.html" },
{ method: "GET", path: "/html/main.html" },
]
module.exports = (req, res, next) => {
//限制需要token认证的接口
const apis = needTokenApi.filter(api => {
const reg = pathToRegexp(api.path);
return api.method === req.method && reg.test(req.path)
});
if (apis.length === 0) {
next();
return;
}
// 获取token解密
let token = req.signedCookies.token
//这个是空的
// let token = req.cookies.token
//如果没有token,赋值header 的authoraization
if (!token) {
//确保可能是手机端或ipad端登录
token = req.headers.authorization;
}
console.log(token);
//如果还是没有 就表示没有登录
if (!token) {
//没有登录就报错,需要登录
next(new Error("请先登录"));
return;
}
//认证通过
next();
}
版权归原作者 悠悠~飘 所有, 如有侵权,请联系我们删除。