目录结构
准备工作: npm init npm i express jsonwebtoken express-jwt
登录.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>首页</title>
</head>
<body>
<div>
<span>用户名:</span>
<input type="text" id="userInp">
</div>
<div>
<span>密码:</span>
<input type="password" id="passInp">
</div>
<div>
<button id="btn">登录</button>
</div>
<script src="./js/axios.min.js"></script>
<script src="./js/jquery3.5.1.js"></script>
<script>
$("#btn").on("click", () => {
var username = $("#userInp").val();
var password = $("#passInp").val();
axios({
url: "http://localhost:3000/api/login",
params: {
username,
password
}
}).then(res => {
if (res.data.status == 1) {
window.location.href = "./首页.html";
}
})
})
</script>
</body>
</html>
首页.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>首页</title>
</head>
<body>
<div id="myDiv"></div>
<button id="outBtn">退出-再刷新就没了</button>
<script src="./js/axios.min.js"></script>
<script src="./js/jquery3.5.1.js"></script>
<script>
axios({
url: "http://localhost:3000/api/getMoney"
}).then(res => {
$("#myDiv").html(res.data.data);
})
$("#outBtn").on("click", () => {
axios({
method: "PUT",
url: "http://localhost:3000/logout"
}).then(res => {
alert(res.data.msg);
window.location.reload();
})
})
</script>
</body>
</html>
22.3_Cookie机制.js
const express = require('express')
const app = express()
app.use(express.static(__dirname + '/public'))
// 模拟用户注册成功的已存在的用户名和密码
let arr = [
{
username: 'lcz',
password: 111111,
money: 10000,
},
{
username: 'xiaoze',
password: 222222,
money: 500,
},
]
// 重要: 跨域后端无法设置前端cookie - 直接在浏览器打开后端的静态资源
// 服务器端, 利用响应头给前端本次请求的位置设置cookie的方式
app.get('/api/login', (req, res) => {
// 假装登录成功了, 设置一个cookie给前端, 比如用户名字
// set-cookie是固定的, 后面的格式固定名称=值 - 去浏览器请求这个接口-观察前端浏览器上被设置了cookie
let { username, password } = req.query
// 查找用户和密码是否有同时匹配的
const have = arr.some(
(obj) => obj.username == username && obj.password == password
)
if (have) {
res.setHeader('set-cookie', `user=${username}; path=/`)
// path代表此cookie在前端生效的区域(发送请求时url只要是在/下, 就都能使用cookie)
res.send({
status: 1,
msg: '登录成功',
})
} else {
res.send({
status: 0,
msg: '账号或密码错误',
})
}
})
// 登录请求-> res返回header 信息(cookie)->客户端
// 再次发请求->自动将cookie放在该请求的请求头中!
app.get('/api/getMoney', (req, res) => {
// 提取cookie, 找到user保存的用户名
let argStr = []
if (req.headers.cookie) {
argStr = req.headers.cookie.split('; ')
}
let username = '' // 保存找到的用户名
argStr.forEach((str) => {
let smallArr = str.split('=')
if (smallArr[0] == 'user') {
username = smallArr[1]
}
})
// 再用用户名, 查询这个用户的金额
let money = 0
arr.forEach((obj) => {
if (obj.username == username) {
money = obj.money
}
})
res.send({
status: 1,
msg: '获取成功',
data: money,
})
})
app.listen(3000, () => {
console.log('服务器启动了')
})
22.4_Session机制.js
const express = require('express')
const app = express()
app.use(express.static(__dirname + '/public'))
let arr = [
{
username: 'lcz',
password: 111111,
money: 10000,
},
{
username: 'xiaoze',
password: 222222,
money: 500,
},
]
// express-session实现session技术
const session = require('express-session')
app.use(
session({
secret: 'keyboard cat', // 用于加密目标数据用的字符串
resave: false, // resave是指每次请求都重新设置session cookie
saveUninitialized: true, // saveUninitialized是指无论有没有session cookie,
// 每次请求都设置个session cookie ,默认给个标示为 connect.sid
})
)
app.get('/api/login', (req, res) => {
let { username, password } = req.query
// 查找用户和密码是否有同时匹配的
const have = arr.some(
(obj) => obj.username == username && obj.password == password
)
if (have) {
// 1 将当前正确的用户的信息保存在内存中
req.session.usern = username
res.send({
status: 1,
msg: '登录成功',
})
} else {
res.send({
status: 0,
msg: '账号或密码错误',
})
}
})
// 重要 - 多个前端登录验证, 需要用不同的浏览器, 因为一个浏览器的同一个域名下的cookie会被覆盖
app.get('/api/getMoney', (req, res) => {
// 提取cookie的值, 从express-session内存中提取对应的值
const username = req.session.usern
console.log(username); // 当前登录的用户名对应的值
// 查找余额
let money = 0
arr.forEach((obj) => {
// 刷卡认证 -> 本人持卡
if (obj.username == username) {
money = obj.money
}
})
res.send({
status: 1,
msg: '获取成功',
data: money,
})
})
app.listen(3000, () => {
console.log('服务器启动了')
})
22.5_删除Session.js
const express = require("express");
const app = express();
app.listen(3000, () => {
console.log("服务器启动了");
})
app.use(express.static(__dirname + "/../1_前端/"));
let arr = [
{
username: "lidongxu",
password: 111111,
money: 10000
},
{
username: "xiaochuan",
password: 222222,
money: 500
}
]
const session = require("express-session");
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
app.get("/api/login", (req, res) => {
let {username, password} = req.query;
const have = arr.some(obj => obj.username == username && obj.password == password);
if (have) {
req.session.usern = username;
res.send({
status: 1,
msg: "登录成功"
})
} else {
res.send({
status: 0,
msg: "账号或密码错误"
})
}
})
app.get("/api/getMoney", (req, res) => {
const username = req.session.usern;
let money = 0;
arr.forEach(obj => {
if (obj.username == username) {
money = obj.money;
}
})
res.send({
status: 1,
msg: "获取成功",
data: money
})
})
app.put("/logout", (req, res) => {
req.session.destroy();
res.send({
status: 1,
msg: "退出成功"
})
})
23.0_jwt基础使用.js
const express = require("express");
const app = express();
// 服务端渲染: session-cookie -> 跨域 cookie用不了->
// 前后端分离(跨域)->jwt.
app.use(express.static(__dirname + "/assets"));
let arr = [
{
username: "lcz",
password: 111111,
money: 10000,
},
{
username: "xiaoze",
password: 222222,
money: 500,
},
];
// 1. 引入模块
const jsonwebtoken = require("jsonwebtoken");
const expressJwt = require("express-jwt");
// 2. 设置秘钥
const secretKey = "itheima No.1 ^.^"; // 钥匙
// 4. 解析 jwt
// 用哪个秘钥解密,
// jwt的算法->HS256
// unless哪些接口不需要权限验证
app.use(
expressJwt({
secret: secretKey,
algorithms: ["HS256"],
}).unless({
path: [/^\/api\//],
})
);
app.get("/api/login", (req, res) => {
let { username, password } = req.query;
const have = arr.some(
(obj) => obj.username == username && obj.password == password
);
if (have) {
// 3. 登录成功 - 生成token
res.send({
status: 1,
msg: "登录成功",
// 注意这个前缀是expressJwt规定的, 必须带这个固定的头加空格, 里面要拆分使用(跟真正jwt数据毫无关系)
// 客户端代码 -> 大事件login->res.data.data.token
token:
"Bearer " +
jsonwebtoken.sign({ username: username }, secretKey, {
// 设置token的有效时长
expiresIn: "24h",
}),
});
// h是小时, s是秒
} else {
res.send({
status: 0,
msg: "账号或密码错误",
});
}
});
app.get("/my/getMoney", (req, res) => {
// 5. 使用req.user.username
const username = req.user.username;
let money = 0;
arr.forEach((obj) => {
if (obj.username == username) {
money = obj.money;
}
});
res.send({
status: 1,
msg: "获取成功",
data: money,
});
});
// 6. 兜底错误处理 - 自定义错误处理中间件
app.use((err, req, res, next) => {
// token 解析失败导致的错误
// UnauthorizedError
if (err.name == "UnauthorizedError") {
return res.send({ status: 401, msg: "无效的token" });
}
res.send({ status: 500, msg: err.message });
});
app.listen(3000, () => {
console.log("服务器启动了");
});