Skip to content
Spotify - 每月低于 10 元

第4章 身份认证

流程:首次访问设置 Cookie -> 解析 Cookie 至 req.cookie -> 登录时将内容存储到 Session 中 -> 通过 Cookie 在 Session 中查询相应的信息

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;
});
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失败后的错误

    js
    app.use((err, req, res, next) => {
        if (err.name === 'UnauthorizedError') {
            return res.send({
                status: 401,
                msg: '无效的token'
            });
        }
        res.send({
            status: 500,
            msg: '未知的错误'
        });
    });
关注微信公众号搬瓦工 - 美国 CN2 优化线路
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0

预览:

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3