本文介绍了JWT的基本概念、工作原理以及实现步骤,帮助读者轻松掌握JWT认证的基础知识。文章详细讲解了JWT生成、解析和验证的过程,并提供了实际应用中的示例代码,确保读者能够理解并应用JWT进行用户校验。JWT用户校验入门还涵盖了JWT在登录、API保护等场景中的应用,以及常见的安全性考虑和刷新机制。
JSON Web Token (JWT) 是一种开放标准 (RFC 7519),用于在各方之间安全地传输信息。JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。这些部分使用 .
分隔符连接在一起形成一个完整的JWT字符串。JWT常用于用户身份验证和授权,由于其轻量级和无状态的特性,使得它非常适用于API接口保护和单点登录(SSO)。
当用户成功登录系统后,服务器会返回一个JWT字符串给客户端。这个字符串包含了用户的标识符以及其他可能的元数据(例如用户名、昵称等)。客户端在后续的HTTP请求中携带这个JWT字符串(通常放在请求头中,如 Authorization: Bearer <token>
),服务器收到请求后会验证JWT的有效性,并根据JWT中的信息来决定是否允许访问资源。
localStorage
)。当接收到来自客户端的请求时,后端服务器需要解析JWT字符串,并验证其有效性:
.
分割,分别获取头部、载荷和签名。const jwt = require('jsonwebtoken'); const secretKey = 'secret'; // 私钥,需要保密 // 解析并验证JWT function verifyToken(req, res, next) { const token = req.headers.authorization.split(' ')[1]; try { const decoded = jwt.verify(token, secretKey); req.user = decoded; next(); } catch (err) { res.status(401).json({ message: 'Invalid token' }); } }
// 示例授权函数 function hasRole(req, res, next) { const role = req.user.role; if (role === 'admin') { next(); } else { res.status(403).json({ message: 'Forbidden' }); } }
首先,需要安装 jsonwebtoken
库。在Node.js环境下,可以通过 npm
安装:
npm install jsonwebtoken
接下来,可以编写一段简单的代码来生成JWT:
const jwt = require('jsonwebtoken'); const secretKey = 'secret'; // 私钥,需要保密 const token = jwt.sign( { userId: '12345', username: 'user1', role: 'admin' }, secretKey, { expiresIn: '1h' // 设置1小时过期时间 } ); console.log(token);
该代码首先定义了一个包含用户ID、用户名和角色的载荷(payload),然后使用jwt.sign()
方法生成JWT字符串。expiresIn
参数指定了JWT的有效期。
在接收到客户端发送的JWT后,服务器可以使用 jsonwebtoken
库来解析和验证这个JWT:
const jwt = require('jsonwebtoken'); const secretKey = 'secret'; // 私钥 try { const decoded = jwt.verify(token, secretKey); console.log('Valid JWT:', decoded); } catch (err) { console.log('Invalid JWT:', err); }
该代码通过jwt.verify()
方法验证JWT的有效性。如果JWT未过期且未被篡改,将返回解析后的载荷对象;否则,会抛出错误。
上述示例代码中,生成JWT时指定了一个secretKey
用于签名,接收JWT时也使用相同的secretKey
进行验证。这是确保JWT安全的关键步骤之一。此外,载荷中包含了用户的身份信息和角色,后端可以根据这些信息进行权限控制。
登录过程中,用户通过用户名和密码提交登录请求。服务器验证用户名和密码后,生成一个JWT并返回给客户端。客户端在后续请求中携带该JWT以证明自己的身份:
// 服务器端 - 登录验证 app.post('/login', (req, res) => { const { username, password } = req.body; // 简化的用户验证逻辑 if (username === 'user1' && password === 'password1') { const token = jwt.sign( { userId: 1, username: 'user1' }, 'secret', { expiresIn: '1h' } ); res.json({ token }); } else { res.status(401).json({ message: 'Unauthorized' }); } }); // 客户端 - 发送登录请求 fetch('/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: 'user1', password: 'password1' }) }) .then(response => response.json()) .then(data => { const token = data.token; localStorage.setItem('token', token); });
服务器可以检查请求头中的JWT,确保只有合法用户才能访问受保护的API接口:
// 服务器端 - 保护API接口 app.get('/protected', (req, res) => { const token = req.headers.authorization.split(' ')[1]; try { const decoded = jwt.verify(token, 'secret'); res.json({ message: 'You are authorized', user: decoded }); } catch (err) { res.status(401).json({ message: 'Unauthorized' }); } }); // 客户端 - 发送受保护的API请求 fetch('/protected', { headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') } }) .then(response => response.json()) .then(data => { console.log(data.message); });
JWT不仅适用于登录和API保护,还可以用于实现单点登录(SSO)、会话管理、跨域资源共享(CORS)等场景。通过JWT,可以减少服务器端的会话管理开销,实现无状态的服务端架构。
单点登录(SSO)允许用户使用一个身份凭证登录多个系统。通过使用JWT,可以轻松实现跨服务的身份验证:
// 服务A - 登录验证 app.post('/login', (req, res) => { const { username, password } = req.body; if (username === 'user1' && password === 'password1') { const token = jwt.sign( { userId: 1, username: 'user1' }, 'secret', { expiresIn: '1h' } ); res.json({ token }); } else { res.status(401).json({ message: 'Unauthorized' }); } }); // 服务B - 验证服务A的JWT app.post('/validate-token', (req, res) => { const token = req.body.token; try { jwt.verify(token, 'secret'); res.json({ message: 'Token valid' }); } catch (err) { res.status(401).json({ message: 'Invalid token' }); } });
JWT的无状态特性使得会话管理变得简单。每次请求都携带JWT,服务器无需存储会话信息:
// 后端 - 会话管理 app.get('/protected', (req, res) => { const token = req.headers.authorization.split(' ')[1]; try { const decoded = jwt.verify(token, 'secret'); res.json({ message: 'You are authorized', user: decoded }); } catch (err) { res.status(401).json({ message: 'Unauthorized' }); } });
JWT可以简化跨域请求的身份验证。服务器只需验证JWT即可确认用户身份:
// 服务器端 - 跨域请求验证 app.use((req, res, next) => { const token = req.headers.authorization.split(' ')[1]; try { jwt.verify(token, 'secret'); next(); } catch (err) { res.status(401).json({ message: 'Unauthorized' }); } });
JWT的有效期通过 expiresIn
参数控制,可以根据应用需求调整过期时间。过短可能导致频繁登录,过长则可能增加安全风险。例如,设置为一天:
jwt.sign( { userId: 1, username: 'user1' }, 'secret', { expiresIn: '1d' } );
当JWT即将过期时,可以通过客户端请求一个新的JWT来刷新,例如:
// 客户端 - 刷新JWT app.post('/refresh', (req, res) => { const token = req.body.token; try { const decoded = jwt.verify(token, 'secret'); const newToken = jwt.sign( { userId: decoded.userId, username: decoded.username }, 'secret', { expiresIn: '1h' } ); res.json({ token: newToken }); } catch (err) { res.status(401).json({ message: 'Unauthorized' }); } }); // 客户端 - 发送刷新请求 fetch('/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token: localStorage.getItem('token') }) }) .then(response => response.json()) .then(data => { const token = data.token; localStorage.setItem('token', token); });
JWT通过无状态的方式简化了用户认证和权限控制。其轻量级的特性使得它非常适合在现代Web应用中使用,尤其是在API接口保护和单点登录中发挥着重要作用。通过正确配置和使用JWT,可以提高应用的安全性和可维护性。
通过这些资源和项目实践,可以进一步加深对JWT的理解和应用能力。