第4章 身份认证
Cookie
流程:首次访问设置 Cookie -> 解析 Cookie 至 req.cookie -> 登录时将内容存储到 Session 中 -> 通过 Cookie 在 Session 中查询相应的信息
解析 Cookie
js
const serverHandle = (req, res) => {
// 1. 将 req.cookie 声明为一个对象
req.cookie = {};
// 2. 获取字符串形式的 cookie
const cookieStr = req.headers.cookie || '';
// 3. 将字符串形式的 cookie 通过 ; 进行划分
cookieStr.split(';').forEach((item) => {
if (!item) {
return;
}
// 4. 解析出 key 与 val 存入 req.cookie 中
const arr = item.split('=');
const key = arr[0].trim();
const val = arr[1].trim();
req.cookie[key] = val;
});
设置 Cookie
js
// 1. 获取 cookie 的过期时间
const getCookieExpires = () => {
const d = new Date();
d.setTime(d.getTime() + 24 * 60 * 60 * 1000);
return d.toGMTString();
};
// 2. 设置 cookie 其中 path 为根路径; httpOnly 防止前端修改; expires 为过期时间
if (needSetCookie) {
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`);
}
Session
直接存储 Session
js
const SESSION_DATA = {};
// 1. 是否需要设置 cookie
let needSetCookie = false;
// 2. 获取 req.cookie 中的 userid
let userId = req.cookie.userid;
if (userId) {
// 3. 若 SESSION_DATA[userId] 不存在,则将其初始化为一个空对象
if (!SESSION_DATA[userId]) {
SESSION_DATA[userId] = {};
}
req.session = SESSION_DATA[userId];
} else {
// 4. 如果 cookie 里没有 userid,就标记为 true
needSetCookie = true;
// 5. 随机生成 userid
userId = `${Date.now()}_${Math.random()}`;
SESSION_DATA[userId] = {};
}
req.session = SESSION_DATA[userId];
配合 Redis 存储
js
// 1. 设置 Session
let needSetCookie = false;
let userId = req.cookie.userid;
if (!userId) {
needSetCookie = true;
userId = `${Date.now()}_${Math.random()}`;
// 初始化 redis 中 session 值
set(userId, {});
}
req.sessionId = userId;
// 2. 获取 Session
get(req.sessionId).then((sessionData) => {
if (sessionData === null) {
// 1. 初始化 Redis 中 session 值
set(req.sessionId, {});
// 2. 设置 session
req.session = {};
} else {
req.session = sessionData;
}
})
// 3. 使用 Session
// 登录成功后,将 username 和 realname 存储到 session
if (data.username) {
// res 设置Set-Cookie
req.session.username = data.username;
req.session.realname = data.realname;
// 同步到 redis 中
set(req.sessionId, req.session);
}
JWT
Session认证机制需要配合Cookie才能实现。Cookie默认不支持跨域访问。
JWT(JSON Web Token)是目前最流行的跨域认证解决方案。
安装JWT相关的包:
npm i jsonwebtoken express-jwt
- jsonwebtoken:用于生成JWT字符串
- express-jwt:将JWT字符串解析还原成JSON对象
定义secret密钥:
const secretKey = 'lbviic^_^';
- 当生成JWT字符串的时候,需要使用secret密钥对用户的信息进行加密,最终得到加密好的JWT字符串
- 当把JWT字符串解析还原成JSON对象的时候,需要使用secret密钥进行解密
生成JWT字符串:调用jsonwebtoken提供的sign()方法
js// 调用jwt.sign()方法生成JWT字符串 // 参数1:用户的信息对象 // 参数2:加密的密钥 // 参数3:配置对象,可以配置当前token的有效期 const token = jwt.sign( { username: userinfo.username }, secretKey, { expiresIn: '30s' } );
将JWT字符串还原为JSON对象
js// 使用app.use()注册中间件 // expressJWT({ secret: secretKey }) 就是用来解析Token的中间件 // .unless({ path: [/^\/api\//] }) 用来指定哪些接口不需要访问权限 app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\/api\//] }))
使用全局错误处理中间件,捕获解析JWT失败后的错误
jsapp.use((err, req, res, next) => { if (err.name === 'UnauthorizedError') { return res.send({ status: 401, msg: '无效的token' }); } res.send({ status: 500, msg: '未知的错误' }); });
预览: