在本文中,我们将了解后端应用程序中使用的基于会话和令牌的身份验证方法。
基于会话的身份验证
简单讲,基于会话(Session)的身份验证使用存储在设备上的特殊代码(Session ID)来记住你访问网站时的身份,保持登录状态并记住你的信息,直到你离开或注销。
还没明白吗?别着急,我们一步一步来看。
用户通过特殊请求通过邮箱和密码发送到服务器来登录。
服务器检查提供的详细信息是否与为用户存储的信息匹配。
如果一切正确,服务器将创建一个保存用户信息(如User ID、权限和时间限制)的“Session”。此信息安全地保存在服务器的存储中,名字可以使用诸如express-session。
服务器将此“会话 ID”发送回用户的设备,通常作为响应中的Cookie。
每当用户想要从服务器获取某些内容时,他们的设备会自动在其请求中包含此会话 ID。
服务器使用此会话 ID 来查找会话存储中存储的有关会话用户的信息。
以下是express-session工作原理:
当用户登录时,服务器会为该用户创建一个会话,并在包含会话 ID 的响应中设置一个 cookie🍪。
浏览器会自动在向服务器发出的后续请求中包含此会话 ID cookie🍪。
当服务器收到请求时,express-session 中间件使用 cookie🍪 中的会话 ID 来检索相关会话数据。
存储在req.session中的数据(例如 userId)可用于处理请求。
如果一切全都匹配,服务器就知道用户是真实的,并响应他们所请求的内容。
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 - JSON Web 令牌)。该令牌保存用户信息(声明),例如 user_id、权限。
该令牌使用密钥进行签名,并使用散列算法(如 SHA256)进行处理以创建散列。
服务器将此令牌发送到客户端,客户端通常将其存储在浏览器中。
客户端可以以不同的方式存储令牌,例如 HttpOnly Cookie、会话存储或本地存储。建议存储在 HttpOnly Cookies 中,因为它可以防止 JavaScript 访问,从而增强针对 XSS 攻击的安全性。
令牌通常有一个过期时间以增强安全性。
对于向服务器发出的每个请求,客户端都会在授权标头中发送令牌。
最好在令牌前加上“Bearer”前缀。
axios.get(URL, {
headers: {
'Authorization': 'Bearer ' + token,
},
})
收到请求后,服务器检索令牌。
使用密钥,服务器验证令牌并从中提取声明。如果声明中的用户信息存在于服务器的用户表中,则服务器会对用户进行身份验证,并授予对所请求资源的访问权限。
//登录
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 });
}
});
});
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) 在携带身份验证之外的附加信息方面提供了更大的灵活性,对于授权和自定义数据传输非常有用。
本文为 @ 场长 创作并授权 21CTO 发布,未经许可,请勿转载。
内容授权事宜请您联系 webmaster@21cto.com或关注 21CTO 公众号。
该文观点仅代表作者本人,21CTO 平台仅提供信息存储空间服务。