全栈开发
文章目录
前言
因为要重构公司的web端产品,和前端一起对了下接口。在对接用户登录的时候,发现当用户关掉浏览器后再次打开浏览器竟然不能无密码登录。然后就和前端商量了下,后端采用jwt技术将生成token给前端,前端将token存储到localstorage,以便后续请求以token方式进行无秘登录以及权限校验。
但是今天在该代码的时候发现后端有用到session进行用户登录的一个校验,似乎和我用的jwt实现的效果有异曲同工之妙,我就好奇了这个和jwt到底有什么区别呢?然后就进行了一番研究…
Session和Jwt是什么?
Session 和 JWT(JSON Web Token) 是两种用于用户身份验证和会话管理的技术,它们各自有不同的特点和应用场景。
Session
概念
Session 是一种服务器端的会话管理技术,用于在用户和服务器之间保持状态信息。Session 通常通过在服务器端存储会话数据来实现。
工作场景
配置
安装需要的库(使用redis作为存储库)。
npm install express-session connect-redis redis
在express中的配置:
const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const redisClient = require('redis').createClient();
const app = express();
// 配置 session 中间件
const session_config = {
store: new RedisStore({ client: redisClient }),
secret: 'your_secret_key', // 用于加密 session ID 的密钥
resave: false, // 是否在每次请求时强制重新保存 session
saveUninitialized: true, // 是否在保存 session 前将其初始化
cookie: {
secure: false, // 在 HTTPS 下设置为 true
maxAge: 3600000 // Cookie 的过期时间(1 小时)
}
}
app.use(session(session_config));
这样,我们就可以开始在express中使用session了。
- 用户登录:
用户提供凭据(如用户名和密码)进行登录。
服务器验证凭据后,生成一个唯一的 Session ID,并将其存储在服务器端的会话存储中(如内存、文件、数据库或 Redis)。
// 示例路由:用户登录
app.post('/login', (req, res) => {
const { userId, passWord } = req.body;
// 在成功登录后存储用户 ID 到会话
req.session.userId = userId;
res.send('User logged in');
});
这样我们就把userId作为用户的唯一Session存到redis中了。
- 发送 Session ID:
服务器将 Session ID 通过 Set-Cookie 头发送到客户端。浏览器会将这个 Session ID 存储在 Cookie 中。这一步不用我们去做,当我们配置好了中间件express会自动帮我们将 Set-Cookie 头发送到客户端
,就是这段代码:
app.use(session(session_config));
- 后续请求:
用户在后续的请求中,浏览器会自动将存储的 Session ID Cookie 发送到服务器。服务器使用 Session ID 查找和检索对应的会话数据,以识别用户并处理请求。比如当我们获取用户信息的时候,我们就可以用浏览器发过来的Session ID Cookie找到对应的Session id的数据,进而取出该Session id的在登录时存储的userId,即req.session.userId
。
// 示例路由:获取用户信息
app.get('/user-info', (req, res) => {
if (req.session.userId) {
res.send(`Logged in as user: ${req.session.userId}`);
} else {
res.send('No user logged in');
}
});
- 关掉浏览器再次打开浏览器无密码登录
上述用户进行登录后,服务器将 Session ID 通过 Set-Cookie 头发送到客户端,用户登录后即使关闭浏览器并重新打开,Cookie 会在客户端保存,保持会话状态。所以当用户再次访问时,浏览器会自动发送保存的 Cookie,服务器能够识别用户并恢复会话。
- 会话管理:
服务器可以根据需要更新或销毁会话数据。例如,用户登出时可以删除对应的 Session 数据。
// 示例路由:用户登出
app.post('/logout', (req, res) => {
req.session.destroy(err => {
if (err) {
return res.status(500).send('Failed to destroy session');
}
res.send('User logged out');
});
});
Jwt
概念
JWT 是一种无状态的身份验证机制,它使用 JSON 对象表示的 Token 来进行用户认证和信息交换。JWT 通常用于在客户端和服务器之间安全地传输信息。
工作场景
配置
npm install express jsonwebtoken
- 用户登录:
首先用户提供凭据进行登录。服务器验证凭据后,生成一个 JWT。JWT通常包含用户的信息(通常是用户 ID 和其他自定义数据)和签名,用于验证 Token 的完整性,然后返回给前端,前端拿到这个Token并存到localStorage,这样就可以将Token持久化存在浏览器里。
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
const secretKey = 'your_secret_key';
app.use(express.json());
app.post('/api/login', (req, res) => {
const { username, password } = req.body;
if (username === 'user' && password === 'password') {
const authToken = jwt.sign({ username }, secretKey, { expiresIn: '1h' });
res.json({ token: authToken });
} else {
res.status(401).json({ message: 'Invalid credentials' });
}
});
- 发送 JWT:
服务器将 JWT 发送给客户端,客户端可以将 JWT 存储在 Cookie、localStorage 或 sessionStorage 中。(跟上面最后有点重复)
- 后续请求:
用户在后续的请求中,将 JWT 通过请求头(如 Authorization: Bearer )发送到服务器。
服务器验证 JWT 的签名和有效性,从中提取用户信息,并处理请求。
前端:
const axios = require('axios');
axios.post('/some-protected-route', {}, {
headers: {
Authorization: `Bearer ${yourJwtToken}`,
},
});
后端:
const jwt = require('jsonwebtoken');
// 中间件验证 JWT
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // 提取 Bearer Token
if (token == null) return res.sendStatus(401); // 如果没有 token,返回 401
jwt.verify(token, 'your_jwt_secret_key', (err, user) => {
if (err) return res.sendStatus(403); // 如果 token 无效,返回 403
req.user = user; // 将解码后的用户信息存储在 req 对象中
next(); // 继续处理请求
});
};
// 使用中间件
app.use('/some-protected-route', authenticateToken, (req, res) => {
// 处理受保护的路由
res.json({ message: 'Access granted', user: req.user });
});
- 关掉浏览器再次打开浏览器无密码登录
// app.js
import axios from 'axios';
import './axiosConfig'; // 引入配置好的 Axios 拦截器
const checkAuthToken = () => {
// 从 localStorage 中获取 JWT
const token = localStorage.getItem('authToken');
if (token) {
// 如果 JWT 存在,设置 Axios 默认请求头
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
// 可选:可以发送请求来验证 token 是否仍然有效
// axios.get('/verify-token')
// .then(response => {
// // Token 仍然有效,继续执行
// })
// .catch(error => {
// // Token 无效或请求失败,处理逻辑(如清除 token 并引导用户登录)
// console.error('Token verification failed', error);
// localStorage.removeItem('authToken');
// // 可能需要引导用户登录
// });
} else {
// 如果 JWT 不存在,引导用户登录或显示登录界面
console.log('No auth token found. Redirecting to login...');
// 例如,重定向到登录页面
window.location.href = '/login';
}
};
// 页面加载时检查 JWT
document.addEventListener('DOMContentLoaded', () => {
checkAuthToken();
});
- 无状态:
由于 JWT 是自包含的,服务器不需要存储会话状态,所有必要的信息都包含在 JWT 中。
总结
session
-
存储位置: 服务器端。
-
机制: 服务器生成和管理会话 ID,客户端通过 Cookie 发送 Session ID。
-
优点:
1.集中管理: Session 数据存储在服务器端,减少了客户端存储的复杂性;
2.安全性: 由于敏感数据(如用户信息)存储在服务器上,相比于存储在客户端,通常更安全;
3.易于实现: 很多后端框架和库都原生支持 session,简化了实现过程;
4.过期管理: Session 过期由服务器控制,不需要客户端进行处理; -
缺点:
1.存储负担: 每个用户的 session 数据都存储在服务器端,可能会消耗大量的服务器内存和存储资源。
2.跨域问题: 依赖于浏览器的 Cookie 机制,这可能会引发跨域问题,尤其是在多个子域名或不同的应用之间。
3.负载均衡: 在分布式系统中,多个服务器处理同一应用时,Session 数据的同步和管理可能变得复杂。需要使用外部存储(如 Redis)来解决这个问题。
jwt
- 存储位置: 客户端。
- 机制: 服务器生成自包含的 Token,客户端通过请求头发送 Token。
- 优点:
1.减少服务器负担: Token 数据存储在客户端,减少了服务器的存储需求。
2.灵活性: 用户可以在多个设备上使用 Token。
3.扩展性: Token 机制是无状态的,服务器不需要存储 session 数据,适合分布式系统和微服务架构。
跨域支持:
4.方便: Token 不依赖于 Cookie,支持在不同的子域名和跨域场景中使用。
5.简化认证:无状态认证: 认证信息包含在 Token 中,简化了每次请求的认证流程。 - 缺点:
1.安全性问题:客户端存储: 存储在客户端,可能被盗取或篡改。需要额外的措施(如 HTTPS、Token 加密)来保护 Token。
2.无法失效: Token 一旦生成,在有效期内都有效,无法像 Session 那样容易地失效或撤销。需要实现刷新 Token 机制来处理 Token 过期问题。
3.复杂性:需要处理 Token 的生成、存储、过期和刷新,可能比 Session 实现要复杂。
4.数据量大: JWT 可以包含很多信息,可能导致 Token 变得较大,影响性能(特别是在请求头中传递时)。
选择 Session 还是 JWT 取决于具体的应用需求和架构设计。在需要集中管理会话状态的传统应用中,Session 可能是更好的选择;而在分布式系统或微服务架构中,JWT 可能更适合。
标签:const,一文,Session,JWT,Jwt,用户,Token,session From: https://blog.csdn.net/hola173841439/article/details/140723646