天天看点

会话身份验证 vs 令牌身份验证:哪个更好?

作者:不秃头程序员
会话身份验证 vs 令牌身份验证:哪个更好?

在本文中,我们将了解后端应用程序中使用的基于会话和令牌的身份验证方法。

基于会话的身份验证

简单讲,基于会话(Session)的身份验证使用存储在设备上的特殊代码(Session ID)来记住你访问网站时的身份,保持登录状态并记住你的信息,直到你离开或注销。

还没明白吗?别着急,我们一步一步来看。

1. 用户登录:

用户通过特殊请求通过邮箱和密码发送到服务器来登录。

2. 检查详情:

服务器检查提供的详细信息是否与为用户存储的信息匹配。

3. 创建会话:

如果一切正确,服务器将创建一个保存用户信息(如User ID、权限和时间限制)的“Session”。此信息安全地保存在服务器的存储中,名字可以使用诸如express-session。

4. 获取会话ID:

服务器将此“会话 ID”发送回用户的设备,通常作为响应中的Cookie。

5. 使用会话 ID:

每当用户想要从服务器获取某些内容时,他们的设备会自动在其请求中包含此会话 ID。

6. 服务器检查:

服务器使用此会话 ID 来查找会话存储中存储的有关会话用户的信息。

以下是express-session工作原理:

  • 当用户登录时,服务器会为该用户创建一个会话,并在包含会话 ID 的响应中设置一个 cookie。
  • 浏览器会自动在向服务器发出的后续请求中包含此会话 ID cookie。
  • 当服务器收到请求时,express-session 中间件使用 cookie 中的会话 ID 来检索相关会话数据。
  • 存储在req.session中的数据(例如 userId)可用于处理请求。

7. 授予访问权限:

如果一切全都匹配,服务器就知道用户是真实的,并响应他们所请求的内容。

会话身份验证 vs 令牌身份验证:哪个更好?

代码例子

下面是一个使用 Express.js 实现会话身份验证的 Node.js 应用程序的示例。

const express = require('express');

const session = require('express-session');

const app = express();

// 中间件设置
app.use(session({
  secret: 'your_secret_key',
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true, // Set the cookie as HTTP-only, Optional
    maxAge: 60*30 // In secs, Optional
  }
}));


//登录

app.post('/login', (req, res) => {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username && u.password === password);

  if (user) {
    req.session.userId = user.id; // Store user ID in session
    res.send('Login successful');
  } else {
    res.status(401).send('Invalid credentials');
  }
});
//受保护页面
app.get('/home', (req, res) => {
  if (req.session.userId) {
    // User is authenticated
    res.send(`欢迎您光临,${req.session.userId}!`);
  } else {
    // User is not authenticated
    res.status(401).send('Unauthorized');
  }
});
//登出
app.get('/logout', (req, res) => {
  req.session.destroy(err => {
    if (err) {
      res.status(500).send('退出登录出现错误');
    } else {
      res.redirect('/'); // Redirect to the home page after logout
    }
  });
});           

基于令牌的身份验证

JWT 身份验证使用包含用户信息的数字签名令牌(Token),其允许对网站或应用程序进行安全且经过验证的访问,而无需重复登录。

让我们看一下基于令牌的身份验证的分步工作流程。

1. 用户登录请求:

用户通过特定请求将电子邮件和密码发送到服务器来登录。

2. 凭证验证:

服务器根据存储的用户数据验证提供的凭据。

3. 代币生成:

验证成功后,服务器会创建一个令牌(通常为 JWT - JSON Web 令牌)。该令牌保存用户信息(声明),例如 user_id、权限。

4. 令牌签名与哈希:

该令牌使用密钥进行签名,并使用散列算法(如 SHA256)进行处理以创建散列。

5. 发送令牌:

服务器将此令牌发送到客户端,客户端通常将其存储在浏览器中。

6. 代币存储选项:

客户端可以以不同的方式存储令牌,例如 HttpOnly Cookie、会话存储或本地存储。建议存储在 HttpOnly Cookies 中,因为它可以防止 JavaScript 访问,从而增强针对 XSS 攻击的安全性。

7. 令牌到期和安全:

令牌通常有一个过期时间以增强安全性。

8. 在请求中包含 Token:

对于向服务器发出的每个请求,客户端都会在授权标头中发送令牌。

最好在令牌前加上“Bearer”前缀。

axios.get(URL, {
    headers: {
        'Authorization': 'Bearer ' + token,
    },
})           

9. 服务器端验证:

收到请求后,服务器检索令牌。

10. 令牌验证和用户认证:

使用密钥,服务器验证令牌并从中提取声明。如果声明中的用户信息存在于服务器的用户表中,则服务器会对用户进行身份验证,并授予对所请求资源的访问权限。

会话身份验证 vs 令牌身份验证:哪个更好?

代码例子

//登录
app.post('/login', (req, res) => {

const { username, password } = req.body;
  const user = users.find(u => u.username === username && u.password === password);

  jwt.sign({ user }, secretKey, { expiresIn: '1h' }, (err, token) => {
    if (err) {
      res.status(500).send('Error generating token');
    } else {
      res.json({ token });
    }
  });
});           

处理保护页面

我们使用veriyToken()函数作为中间件来处理每条需要验证的路由。请求通过,veriyToken()并且仅当next()调用该函数时,它才会传递到该路由并实现代码。

app.get('/dashboard', verifyToken, (req, res) => {
  res.send('Welcome to the Home page');
});

// Verify token middleware
function verifyToken(req, res, next) {
  const token = req.headers['authorization'];

  if (typeof token !== 'undefined') {
    jwt.verify(token.split(' ')[1], secretKey, (err, decoded) => {
      if (err) {
        res.status(403).send('Invalid token');
      } else {
        req.user = decoded.user;
        next();
      }
    });
  } else {
    res.status(401).send('Unauthorized');
  }
}           

两种方法的差异

  • 存储位置:会话存储在服务器上,而令牌(JWT)存储在客户端。
  • 有状态与无状态:会话是有状态的,而令牌是无状态的,从而可以在分布式系统中实现更好的可扩展性。
  • 过期处理:会话过期由服务器管理,而令牌过期由令牌本身处理。
  • 安全措施:JWT 通常包括数字签名和加密支持,与使用 cookie 的典型会话机制相比增强了安全性,并且如果保护不当,可能容易受到 CSRF 攻击。
  • 使用灵活性:令牌 (JWT) 在携带身份验证之外的附加信息方面提供了更大的灵活性,对于授权和自定义数据传输非常有用。

应该使用哪种方法?

这取决于应用程序的要求和性质。大多数应用程序会使用混合方法,即针对 API 的基于令牌的身份验证,以及针对基于 Web 的交互的基于会话的身份验证。