JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在网络上以紧凑且自包含的方式安全地传输信息。JWT 被设计为在用户和服务之间传递声明信息,以便进行身份验证和授权。该标准定义了一种简洁的、自包含的方法,可以传递使用 JSON 对象进行编码的信息,这些信息可以被验证和信任。
JWT 由三个部分组成:Header、Payload 和 Signature。这三部分通过.
符号分隔,并以Base64编码的形式进行表示。
Header(头部):
{
"alg": "HS256",
"typ": "JWT"
}
Payload(负载):
Payload 包含了声明(claims)。声明是关于实体(通常是用户)和其他数据的声明。有三种类型的声明:
iss
(签发者)、sub
(主题)、aud
(受众)、exp
(过期时间)、nbf
(不可用之前的时间)和 iat
(发布时间)。例如:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
Signature(签名):
使用编码的 header、编码的 payload 和一个秘密密钥来创建签名部分。签名用于验证消息在传递过程中是否被篡改。
例如:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
JWT 的工作流程通常如下:
Authorization
头部)中。优势和特点:
需要注意的是,由于 JWT 使用了 Base64 编码,虽然可以在客户端解码查看,但不能修改,因为修改后签名验证将失败。然而,JWT 中的信息仍然是可见的,因此敏感信息应该被妥善处理。
编写一个完整的 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、存储更安全的密钥、使用数据库进行用户验证等。
客户端部分通常是一个前端应用,可以使用 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" id="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,并使用该令牌向服务器发起受保护路由的请求。
请注意,这只是一个基础示例,实际项目中应该考虑更多的安全性和用户体验问题。前端应用通常会使用一些框架,以更好地组织和管理代码。
以下是一个使用 Mermaid 语法绘制的简单 JWT 流程图:
这个流程图简要描述了 JWT 的使用过程:
请注意,这只是一个高层次的概述,实际流程可能因应用场景而异,例如,在生成 JWT 时可能涉及更多的步骤,而在验证 JWT 时可能涉及更多的安全性检查。