文章目录
- 一、JWT理论基础
- 二、JWT使用实例
-
- 2.1 服务端代码
- 2.2 客户端代码
- 三、JWT流程
一、JWT理论基础
JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在网络上以紧凑且自包含的方式安全地传输信息。JWT 被设计为在用户和服务之间传递声明信息,以便进行身份验证和授权。该标准定义了一种简洁的、自包含的方法,可以传递使用 JSON 对象进行编码的信息,这些信息可以被验证和信任。
JWT 由三个部分组成:Header、Payload 和 Signature。这三部分通过.
符号分隔,并以Base64编码的形式进行表示。
-
Header(头部):
- Header 包含了两部分信息,分别是 token 的类型(JWT)和使用的签名算法,例如:
{ "alg": "HS256", "typ": "JWT" }
- 上述例子表示使用 HMAC SHA-256 算法进行签名。
- Header 包含了两部分信息,分别是 token 的类型(JWT)和使用的签名算法,例如:
-
Payload(负载):
-
Payload 包含了声明(claims)。声明是关于实体(通常是用户)和其他数据的声明。有三种类型的声明:
-
注册声明(Registered claims): 这些是一组预定义的声明,包括
iss
(签发者)、sub
(主题)、aud
(受众)、exp
(过期时间)、nbf
(不可用之前的时间)和iat
(发布时间)。 - 公共声明(Public claims): 可以根据需要定义的声明。
- 私有声明(Private claims): 用于在同意使用它们的双方之间共享信息。
-
注册声明(Registered claims): 这些是一组预定义的声明,包括
-
例如:
{ "sub": "1234567890", "name": "John Doe", "admin": true }
-
-
Signature(签名):
-
使用编码的 header、编码的 payload 和一个秘密密钥来创建签名部分。签名用于验证消息在传递过程中是否被篡改。
-
例如:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
-
JWT 的工作流程通常如下:
- 用户进行身份验证,并且身份验证成功后,服务器会生成一个包含用户信息的 JWT,并将其返回给用户。
- 用户在之后的请求中将 JWT 放入请求的头部(通常是
Authorization
头部)中。 - 服务器在接收到请求时,使用之前共享的密钥来验证 JWT 的签名,以确保信息的完整性。
- 如果签名验证成功,服务器可以使用 JWT 中的信息进行授权判断。
优势和特点:
- 简洁性: JWT 使用 JSON 数据格式,具有良好的可读性和编码/解码的便捷性。
- 自包含: JWT 包含了所有需要的信息,避免了每次请求时都需要查询数据库的开销。
- 可靠性: JWT 的签名机制保证了消息的完整性,防止了信息被篡改的可能性。
- 跨域: 可以在不同的域之间进行信息传递,支持跨域应用场景。
需要注意的是,由于 JWT 使用了 Base64 编码,虽然可以在客户端解码查看,但不能修改,因为修改后签名验证将失败。然而,JWT 中的信息仍然是可见的,因此敏感信息应该被妥善处理。
二、JWT使用实例
2.1 服务端代码
编写一个完整的 JWT 项目涉及多个方面,包括用户认证、生成和验证 JWT、路由保护等。下面是一个简单的示例,使用 Node.js 和 Express 框架实现:
首先,确保你已经安装了 Node.js 和 npm。然后,创建一个新目录,执行以下步骤:
-
初始化项目:
npm init -y
-
安装依赖:
npm install express jsonwebtoken body-parser
-
创建一个
server.js
文件:const express = require('express'); const jwt = require('jsonwebtoken'); const bodyParser = require('body-parser'); const app = express(); const PORT = 3000; const SECRET_KEY = 'your_secret_key'; app.use(bodyParser.json()); // 用户数据库(示例) const users = [ { id: 1, username: 'user1', password: 'password1' }, { id: 2, username: 'user2', password: 'password2' }, ]; // 登录路由 app.post('/login', (req, res) => { const { username, password } = req.body; // 实际项目中应该通过数据库查询验证用户信息 const user = users.find((u) => u.username === username && u.password === password); if (user) { // 生成 JWT const token = jwt.sign({ userId: user.id, username: user.username }, SECRET_KEY, { expiresIn: '1h' }); res.json({ token }); } else { res.status(401).json({ error: 'Invalid credentials' }); } }); // 保护路由 app.get('/protected', (req, res) => { const token = req.header('Authorization'); if (!token) { return res.status(401).json({ error: 'Unauthorized' }); } // 验证 JWT jwt.verify(token, SECRET_KEY, (err, decoded) => { if (err) { return res.status(401).json({ error: 'Invalid token' }); } res.json({ message: 'You are authorized!', user: decoded }); }); }); app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); });
-
运行应用:
node server.js
现在,你的应用将在 http://localhost:3000
上运行。你可以使用 Postman 或其他工具模拟登录请求,然后将生成的 token 用于访问 /protected
路由。
请注意,以上示例是一个简单的演示,实际项目中需要更复杂的用户认证和安全性措施。在生产环境中,你可能需要使用 HTTPS、存储更安全的密钥、使用数据库进行用户验证等。
2.2 客户端代码
客户端部分通常是一个前端应用,可以使用 HTML、CSS、JavaScript(通常使用框架如 React、Vue.js 或 Angular)来实现。在客户端,主要任务包括用户界面的设计、用户登录、JWT 的处理、以及向服务器发起请求等。
以下是一个简单的 HTML、CSS、JavaScript 示例,使用原生 JavaScript 实现:
- 创建一个
index.html
文件:
DOCTYPE html>
html lang="en">
head>
meta charset="UTF-8">
meta name="viewport" content="width=device-width, initial-scale=1.0">
title>JWT Demo - Clienttitle>
head>
body>
h1>JWT Demo - Clienth1>
div id="login-form">
label for="username">Username:label>
input type="text" id="username" required>
br>
label for="password">Password:label>
input type="password" i服务器托管网d="password" required>
br>
button onclick="login()">Loginbutton>
div>
div id="protected-content" style="display: none;">
h2>Protected Contenth2>
p id="message">p>
div>
script>
function login() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
fetch('http://localhost:3000/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
})
.then(response => response.json())
.then(data => {
if (data.token) {
// 登录成功,显示保护内容
document.getElementById('login-form').style.display = 'none';
document.getElementById('protected-content').style.display = 'block';
document.getElementById('message').innerText = 'Loading...';
// 使用获取的 token 访问受保护的路由
fetch('http://localhost:3000/protected', {
headers: {
'Authorization': data.token,
},
})
.then(response => response.json())
.then(protectedData => {
document.getElementById('message').innerText = `Welcome, ${protectedData.user.username}!`;
})
.catch(error => console.error('Error fetching protected content:', error));
} else {
alert('Invalid credentials');
}
})
.catch(error => console.error('Login error:', error));
}
script>
body>
html>
这个简单的 HTML 文件包含一个登录表单和一个显示受保护内容的部分。当用户成功登录后,它会获取 JWT,并使用该令牌向服务器发起受保护路由的请求。
请注意,这只是一个基础示例,实际项目中应该考虑更多的安全性和用户体验问题。前端应用通常会使用一些框架,以更好地组织和管理代码。
三、JWT流程
以下是一个使用 Mermaid 语法绘制的简单 JWT 流程图:
#mermaid-svg-6veo4UcQSJWvDoq6 {font-family:”trebuchet ms”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6veo4UcQSJWvDoq6 .error-icon{fill:#552222;}#mermaid-svg-6veo4UcQSJWvDoq6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6veo4UcQSJWvDoq6 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-6veo4UcQSJWvDoq6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6veo4UcQSJWvDoq6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6veo4UcQSJWvDoq6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6veo4UcQSJWvDoq6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6veo4UcQSJWvDoq6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6veo4UcQSJWvDoq6 .marker.cross{stroke:#333333;}#mermaid-svg-6veo4UcQSJWvDoq6 svg{font-family:”trebuchet ms”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6veo4UcQSJWvDoq6 .label{font-family:”trebuchet ms”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-6veo4UcQSJWvDoq6 .cluster-label text{fill:#333;}#mermaid-svg-6veo4UcQSJWvDoq6 .cluster-label span{color:#333;}#mermaid-svg-6veo4UcQSJWvDoq6 .label text,#mermaid-svg-6veo4UcQSJWvDoq6 span{fill:#333;color:#333;}#mermaid-svg-6veo4UcQSJWvDoq6 .node rect,#mermaid-svg-6veo4UcQSJWvDoq6 .node circle,#mermaid-svg-6veo4UcQSJWvDoq6 .node ellipse,#mermaid-svg-6veo4UcQSJWvDoq6 .node polygon,#mermaid-svg-6veo4UcQSJWvDoq6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6veo4UcQSJWvDoq6 .node .label{text-align:center;}#mermaid-svg-6veo4UcQSJWvDoq6 .node.clickable{cursor:pointer;}#mermaid-svg-6veo4UcQSJWvDoq6 .arrowheadPat服务器托管网h{fill:#333333;}#mermaid-svg-6veo4UcQSJWvDoq6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6veo4UcQSJWvDoq6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6veo4UcQSJWvDoq6 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-6veo4UcQSJWvDoq6 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-6veo4UcQSJWvDoq6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6veo4UcQSJWvDoq6 .cluster text{fill:#333;}#mermaid-svg-6veo4UcQSJWvDoq6 .cluster span{color:#333;}#mermaid-svg-6veo4UcQSJWvDoq6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:”trebuchet ms”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6veo4UcQSJWvDoq6 :root{–mermaid-font-family:”trebuchet ms”,verdana,arial,sans-serif;}
这个流程图简要描述了 JWT 的使用过程:
- 用户提供用户名和密码。
- 服务器验证用户信息。
- 如果验证成功,服务器生成 JWT。
- 服务器将包含 JWT 的响应发送给用户。
- 用户在后续请求中包含 JWT。
- 服务器验证 JWT 并授权用户访问受保护资源。
请注意,这只是一个高层次的概述,实际流程可能因应用场景而异,例如,在生成 JWT 时可能涉及更多的步骤,而在验证 JWT 时可能涉及更多的安全性检查。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
Databend 是一款现代云数仓。专为弹性和高效设计,为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务:https://app.databend.cn 。 What’s On In Databend 探索 Databend 本周新进展,遇到更贴近你心…