17611538698
webmaster@21cto.com

会话身份验证 vs 令牌身份验证:孰优孰劣?

安全 0 887 2024-04-24 02:03:43

图片

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

基于会话的身份验证

简单讲,基于会话(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. 授予访问权限:

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

图片

代码例子


下面是一个使用 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. 令牌验证和用户认证:

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

图片

代码例子


//登录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 middlewarefunction 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 的交互的基于会话的身份验证。


希望你喜欢这篇文章。如果对你有用,请不要忘记点赞转发!对了,你的项目使用哪种后端语言?欢迎在文底发表评论~🤔

评论