Web身份认证——【 Cookie认证 】
学习目标:
1、什么是身份认证?
身份认证又称“验证”、“鉴权”,是指通过一定的手段,完成对用户身份的确认。日常生活中无处不见身份认证的踪影,比如:高铁的验票乘车、手机的密码、指纹或面部识别解锁、支付宝或者微信的支付密码……等,都是身份验证的真是写照。
当然,在Web开发中,也涉及到了用户身份的认证,例如:各大网站的手机验证码登录、邮箱密码登录、二维码登录……等,都需要我们对用户的身份进行进一步的验证,否则将存在不安全的隐患。
2、为什么需要身份认证?
从广义上来讲,身份认证的目的简单来说就是消除一些不安全的隐患,给用户的财产安全以最大的保护。但从专业术语来讲,身份认证的目的是确认当前所声称为某种身份的用户,确实是所声称的用户。
虽然日常生活中对身份认证的做法属于广义的“身份认证”,但“身份认证”一词更多地被用在计算机、通信等领域上。
3、HTTP协议的无状态性
了解HTTP协议的无状态性是进一步学习Session认证机制
的必要前提。HTTP协议的无状态性是指:客户端的每次HTTP请求都是独立的,连续多个请求之间没有直接的关系,并且服务器不会主动保留每次的HTTP请求的状态。
例1:用户登录
比如验证用户是否登录的时候,只能判断密码和账号是否正确,才能让其登录,那么此时HTTP不会记录其登录状态,当下一次来访问该网站的时候还需要提供正确的账号和密码,才能访问。或者当用户登录该网站后,要访问该网站下的其他子网页还需要再让用户登录嘛?但是我们也不能让登录进来的都访问吧,所以我们只需要通过验证用户此时的身份才能让其访问。
例2:超市收银
比如每个超市都有VIP用户和普通用户,我们都将其看作是客户端,而超市的收银员我们可以看做是HTTP协议,那么当客户来购买商品的时候,如果没有会员卡和记录,收银员如何判断来的用户哪个是VIP用户,哪个是普通用户,又该给谁打折呢,那么这种情况下就是HTTP协议的无状态性。
4、如何突破HTTP协议的无状态的限制?
对于超市而言,为了方便收银员在进行结算时给VIP用户打折,超市可以给VIP用户发放会员卡,这样超市收银员就可以根据用户手中的会员卡来很轻松的识别VIP用户。
而现实生活中这种会员卡的认证方式,在Web开发中的专业属于叫Cookie认证,是一门认证技术。
5、Cookie认证
5.1 概念
Cookie
是存储在用户浏览器中一段不超过 4KB 的字符串。它由一个名称(Name)、一个值(value)和其他几个用户控制 Cookie 有效期、安全性、使用范围的可选属性组成,并且Name和Value是以键值对{key:value}
的形式存在的。
5.2 特点
- 自动发送:每当客户端发起请求时,浏览器会自动将当前域名下所有未过期的 Cookie 一同发送到服务器
- 域名独立:不同域名下的 Cookie 各自独立,互不影响
- 过期限制:Cookie值具有时效性,如果超出了期限,将不起作用,在服务器内也无法验证通过
- 4 KB 限制:Cookie 是存储在用户浏览器中一段不超过 4KB 的字符串
5.3 Cookie认证机制
客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的 Cookie,客户端会自动将其保存在浏览器中。
随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的 Cookie 通过请求头的形式发送到服务器,那么此时服务器就可以验明客户端的身份。
6、Node.js实现Cooke认证
- 首先导入express模块,并搭建服务器
// 导入express模块
const express = require("express");
// 创建服务器
const app = express();
// 监听并开启服务器
app.listen(8080, "192.168.124.15", () => {
console.log("服务器开启成功!");
});
- 然后对cookie进行设置
格式:
res.cookie(name[string], value[string/object], option[object];
说明:
1、name:Cookie的名称,string类型
2、value:Cookie的值,string或者object类型
3、option:对Cookie进行设置的属性,object类型
例如:
res.cookie("user", { "uid": 10000, "islogin": true }, { maxAge: 9000 });
option可使用的属性如下:
1、`domain`:cookie在什么域名下有效,类型为string,默认为网站域名导入**cookie-parser**中间件,并使用它解析请求头中 Cookie 值
2、`expires`:cookie的过期时间,类型为Date,如果没有设置,或者设置为0,那么该cookie只在这个session有效,即关闭服务器后,这个cookie会被浏览器删除
3、`httpOnly`:只能被 web server访问,即当前js脚本服务器,类型为`Boolean`
4、`maxAge`:实现`expires`的功能,即设置cookie过期的时间,类型为string,指明从现在开始,多少毫秒以后,cookie失效
5、`path`:cookie在什么路径下有效,默认为`'/'`,类型为string
6、`secure`:只能被HTTPS使用,类型为`Boolean`,默认为false
7、`signed`:使用签名,类型为`Boolean`,默认为false,express会使用req.secret来完成签名,需要配合`cookie-parser`使用
cookie的删除:res.clearCookie(name:string,options?:any);
-
导入
cookie-parser
模块,并使用该模块,自动对客户端响应头形式传过来的cookie进行解析1、首先先在当前项目下安装 cookie-parser 第三方中间件 npm i cookie-parser 2、导入该模块 const cookie = require("cookie-parser"); 3、使用该中间件,并且设置签名,当然也可以不设置签名,那就是没有参数 app.use(cookie("InLett"));
-
判断传过来的值是否正确
// 判断cookie中的值是否为位定义 if (req.cookies.user === undefined) { res.send({ status: 1, msg: "用户未登录" }); } else if (req.cookies.user.uid === "10000" && req.cookies.user.islogin) { //如果cookie中的值正确,则读取html中的文件,给客户端响应 fs.readFile(path.join(__dirname, "../client/index.html"), "utf8", (err, data) => { // 替换data中的字符 data = data.replace("--", req.cookies.user.uid); res.send(data); }); }
7、用户登录案例
**需求:**用户第一次登录时设置cookie,当访问该域名下的其他接口,则使用cookie进行身份认证,不成功则重新登录,否则现实网页数据
![Cookie的缺点](E:\后端\node.js\笔记\images\Cookie的缺点.jpg)// 导入express模块
const express = require("express");
// 导入fs模块
const fs = require("fs");
// 导入path模块
const path = require("path");
// 服务器对象
const app = express();
// 路由对象
const router = express.Router();
// 导入解析cookie的模块
const cookie = require("cookie-parser");
// 解析json数据
app.use(express.json());
// 解析x-www-form-urlencoded 表单数据
app.use(express.urlencoded({ extended: false }));
//解析cookie加密数据,并设置签名
app.use(cookie("index"));
// 当前路由下接口
router.get("/", (req, res) => {
// 读取html中的数据。响应给客户端
fs.readFile(path.join(__dirname, "../client/login.html"), "utf8", (err, data) => {
res.send(data);
});
});
// 登录请求
router.post("/login", (req, res) => {
// 判断账号和密码
if (req.body.uid !== "10000" || req.body.pwd !== "admin") {
return res.send("用户信息有误,登录失败!");
}
// 设置cookie值,记录用户账号和登录状态,并设置时效为900000毫秒,使用签名
res.cookie("user", { "uid": "10000", "islogin": true }, { maxAge: 900000, signed: true });
res.send("登录成功!");
});
// 当前网站下的其他网页
router.get("/index", (req, res) => {
// 判断客户端是否存在cookies.user
if (req.cookies.user === undefined) {
res.send({
status: 1,
msg: "用户未登录"
});
} else if (req.cookies.user.uid === "10000" && req.cookies.user.islogin) {
//身份验证通过则读取html文件,响应给客户端
fs.readFile(path.join(__dirname, "../client/index.html"), "utf8", (err, data) => {
// 替换data中的字符
data = data.replace("--", req.cookies.user.uid);
res.send(data);
});
}
});
// 使用路由对象
app.use(router);
// 监听服务器,并开启服务器
app.listen(8080, "192.168.124.15", () => {
console.log("服务器开启成功!");
});
8、cookie 不具有安全性
由于 Cookie 是存储在用户浏览器中的,并且浏览器也提供了读写 Cookie 的Api,因此 Cookie 很容易被截获和伪造,所有它不具有安全性,因此不建议服务器将重要的隐私数据通过 Cookie 的形式发送给客户端浏览器。
总结:
千万不要使用 Cookie 存储重要且隐私的数据!比如用户的身份信息、密码……等。