为了账号安全,请及时绑定邮箱和手机立即绑定

JWT项目实战:从入门到应用

标签:
安全 API
概述

JWT项目实战涵盖了JWT的基本原理、优势和应用场景,从环境搭建到实际代码实现,详细介绍了JWT在项目中的应用,包括身份验证、授权以及在前后端分离项目和移动应用中的具体应用。

JWT项目实战:从入门到应用
JWT简介与原理

什么是JWT

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用环境之间安全地传输信息。JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。这一标准是由IETF提出并且得到广泛支持。JWT的主要应用是通过身份验证、授权,以及在分布式环境中安全传输信息。

JWT的工作原理

JWT的工作原理可以概括为以下几个步骤:

  1. 生成JWT:服务器端使用算法(如HMAC,RSA等)生成一个JWT。
  2. 加密JWT:使用密钥(如果使用非对称加密算法如RSA,则使用公钥)对JWT进行加密。
  3. 颁发JWT:将加密后的JWT返回给客户端。
  4. 存储JWT:客户端将JWT存储在本地,可以选择存储在localStoragesessionStorage中,或设置为Cookie
  5. 发送JWT:每次客户端请求资源时,将JWT作为HTTP请求头的一部分发送给服务器。
  6. 验证JWT:服务器接收到请求后,使用密钥(如果是使用非对称加密算法,使用私钥)对JWT进行解密并验证。
  7. 授权资源:如果JWT有效,则根据载荷中的信息进行权限验证,返回授权资源。

JWT的优势

JWT的优势包括:

  • 无状态:服务器无须存储JWT,节省了存储资源。
  • 安全性:使用密钥加密,安全性高。
  • 跨域支持:支持跨域请求,便于前后端分离应用。
  • 广泛支持:几乎所有的现代编程语言都有JWT库支持。

JWT的应用场景

JWT的应用场景包括:

  • 身份验证:用户登录后,服务器生成JWT,用户可以通过JWT访问受保护的资源。
  • 授权:根据JWT中的信息实现细粒度的权限控制。
  • 分布式系统:在分布式系统中,JWT可以用于不同节点间的安全通信。
环境搭建与准备工作

开发工具的安装

为了开发JWT项目,你将需要以下几个工具:

  • Node.js & npm: 下载并安装最新的Node.js和npm。
  • 编辑器: 可以选择Visual Studio Code、Sublime Text、WebStorm等。

开发环境的配置

创建一个新的项目目录:

mkdir jwt-project
cd jwt-project

初始化一个新的Node.js项目:

npm init -y

必要库的引入与安装

安装JWT库jsonwebtoken和HTTP库express

npm install jsonwebtoken express

安装完成后,项目的package.json文件中将包含以下依赖:

"dependencies": {
  "express": "^4.18.1",
  "jsonwebtoken": "^9.0.0"
}
创建JWT并理解其结构

如何生成JWT

使用jsonwebtoken库生成JWT:

const jwt = require('jsonwebtoken');

const token = jwt.sign({ userId: 123 }, 'secret', { expiresIn: '1h' });
console.log(token);

上述代码生成了一个带有用户标识userId的JWT,并设定了有效期为1小时。

JWT的结构解析

JWT由三部分组成,各部分之间用点号.分隔:

  1. 头部(Header):是一个JSON对象,描述令牌的类型(JWT)以及签名所使用的算法,默认是HMAC SHA256。
  2. 载荷(Payload):载荷是JWT的核心,是包含在JWT中的声明列表。例如,用户ID、用户名、权限等信息。
  3. 签名(Signature):使用头部声明的算法对头部和载荷进行签名。

加密算法的选择与应用

常用的加密算法包括HMAC、RSA、ECDSA等。其中HMAC使用一个密钥进行签名,RSA和ECDSA使用公钥私钥对进行签名。

示例代码使用HMAC算法生成JWT:

const jwt = require('jsonwebtoken');

const payload = { userId: 123 };
const secret = 'mySecret';

const token = jwt.sign(payload, secret, { algorithm: 'HS256' });
console.log(token);
使用JWT进行身份验证

基础身份验证流程

  1. 登录:用户登录后,服务器生成JWT。
  2. 存储JWT:客户端将JWT存储起来,通常存储在localStorage中。
  3. 发送JWT:客户端每次请求资源时,将JWT置于请求头的Authorization字段中。
  4. 验证JWT:服务器接收到请求后,验证JWT的有效性。
  5. 授权资源:验证通过后,服务器返回请求的资源。

使用JWT实现登录功能

创建一个简单的登录接口,生成JWT并返回给客户端:

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

app.post('/login', (req, res) => {
  const user = { userId: 123 };
  const token = jwt.sign(user, 'secret', { expiresIn: '1h' });
  res.json({ token });
});

app.listen(3000, () => console.log('Server running on port 3000'));

客户端通过登录接口请求JWT:

// JavaScript前端代码
fetch('/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ username: 'john', password: 'password' })
})
.then(response => response.json())
.then(data => localStorage.setItem('token', data.token));

解析并验证JWT令牌

在路由处理函数中验证JWT:

const secret = 'secret';

app.get('/protected', (req, res) => {
  const token = req.header('Authorization').replace('Bearer ', '');
  try {
    const decoded = jwt.verify(token, secret);
    res.status = 200;
    res.json({ userId: decoded.userId });
  } catch (err) {
    res.status = 401;
    res.json({ message: 'Invalid token' });
  }
});

客户端请求受保护的资源:

// JavaScript前端代码
fetch('/protected', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer ' + localStorage.getItem('token')
  }
})
.then(response => response.json())
.then(data => console.log(data));
JWT在项目中的实际应用

JWT在前后端分离项目中的应用

前后端分离项目中,前端负责页面展示,后端负责业务逻辑和数据存储。在这样的架构下,JWT非常适合用来实现前后端之间的安全通信。

示例代码:

后端(Express):

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

// 登录接口
app.post('/login', (req, res) => {
  const user = { userId: 123 };
  const token = jwt.sign(user, 'secret', { expiresIn: '1h' });
  res.json({ token });
});

// 受保护的资源
app.get('/protected', (req, res) => {
  const token = req.header('Authorization').replace('Bearer ', '');
  try {
    const decoded = jwt.verify(token, 'secret');
    res.json({ userId: decoded.userId });
  } catch (err) {
    res.status = 401;
    res.json({ message: 'Invalid token' });
  }
});

app.listen(3000, () => console.log('Server running on port 3000'));

前端(JavaScript):

// 登录
fetch('/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ username: 'john', password: 'password' })
})
.then(response => response.json())
.then(data => localStorage.setItem('token', data.token));

// 请求受保护的资源
const token = localStorage.getItem('token');
fetch('/protected', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer ' + token
  }
})
.then(response => response.json())
.then(data => console.log(data));

JWT在移动应用中的应用

在移动应用中,可以使用JWT实现用户认证和授权。例如在Android中,可以使用OkHttp库来发送带有JWT的HTTP请求。

示例代码(Java):

后端(Express):

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

app.post('/login', (req, res) => {
  const user = { userId: 123 };
  const token = jwt.sign(user, 'secret', { expiresIn: '1h' });
  res.json({ token });
});

app.get('/protected', (req, res) => {
  const token = req.header('Authorization').replace('Bearer ', '');
  try {
    const decoded = jwt.verify(token, 'secret');
    res.json({ userId: decoded.userId });
  } catch (err) {
    res.status = 401;
    res.json({ message: 'Invalid token' });
  }
});

app.listen(3000, () => console.log('Server running on port 3000'));

前端(Android):

import okhttp3.*;

public class MainActivity extends AppCompatActivity {
    private OkHttpClient client = new OkHttpClient();

    public void login() {
        RequestBody body = new FormBody.Builder()
                .add("username", "john")
                .add("password", "password")
                .build();

        Request request = new Request.Builder()
                .url("http://localhost:3000/login")
                .post(body)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String token = response.body().string();
                SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
                prefs.edit().putString("jwt", token).apply();
            }
        });
    }

    public void requestProtectedResource() {
        SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
        String token = prefs.getString("jwt", null);

        Request request = new Request.Builder()
                .url("http://localhost:3000/protected")
                .addHeader("Authorization", "Bearer " + token)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String json = response.body().string();
                JSONObject obj = new JSONObject(json);
                Log.d("Response", obj.getString("userId"));
            }
        });
    }
}

JWT在RESTful API中的使用

在RESTful API中,JWT可以用于实现无状态的身份验证。每个请求都需要携带JWT,服务器端可以验证JWT的有效性。

示例代码:

后端(Express):

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

app.post('/login', (req, res) => {
  const user = { userId: 123 };
  const token = jwt.sign(user, 'secret', { expiresIn: '1h' });
  res.json({ token });
});

app.get('/protected', (req, res) => {
  const token = req.header('Authorization').replace('Bearer ', '');
  try {
    const decoded = jwt.verify(token, 'secret');
    res.json({ userId: decoded.userId });
  } catch (err) {
    res.status = 401;
    res.json({ message: 'Invalid token' });
  }
});

app.listen(3000, () => console.log('Server running on port 3000'));

前端(JavaScript):

// 登录
fetch('/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ username: 'john', password: 'password' })
})
.then(response => response.json())
.then(data => localStorage.setItem('token', data.token));

// 请求受保护的资源
const token = localStorage.getItem('token');
fetch('/protected', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer ' + token
  }
})
.then(response => response.json())
.then(data => console.log(data));
常见问题与解决方案

JWT的存储与安全性

JWT的存储有几种选择:

  1. Cookie:可以使用httpOnly选项防止前端JavaScript访问,从而防止跨站脚本攻击。
  2. LocalStorage:存储在客户端的内存中,适合前端JavaScript操作。
  3. SessionStorage:类似于LocalStorage,但每个窗口都有独立的存储空间。

安全性注意事项:

  • 密钥安全:JWT的安全性依赖于密钥的安全性,密钥必须保密。
  • HTTPS:确保所有请求都是通过HTTPS,防止中间人攻击。
  • 过期时间:设置合理的过期时间,过期后需要重新登录或刷新令牌。

错误排查与常见问题解答

常见的问题包括:

  • JWT无效:确保密钥一致,过期时间内有效。
  • 权限问题:确保JWT中的权限信息正确。

JWT的过期与刷新机制

JWT通常设置过期时间,过期后需要重新登录或刷新令牌。

刷新令牌的过程:

  1. 生成刷新令牌:在用户登录时,可以生成一个刷新令牌,存储在后端数据库中。
  2. 刷新令牌请求:当JWT过期时,客户端使用刷新令牌请求新的JWT。

示例代码:

后端(Express):

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

// 登录接口
app.post('/login', (req, res) => {
  const user = { userId: 123 };
  const jwtToken = jwt.sign(user, 'jwtSecret', { expiresIn: '1h' });
  const refreshToken = jwt.sign(user, 'refreshSecret', { expiresIn: '7d' });
  res.json({ token: jwtToken, refreshToken: refreshToken });
});

// 刷新令牌接口
app.post('/refresh', (req, res) => {
  const refreshToken = req.body.refreshToken;
  try {
    jwt.verify(refreshToken, 'refreshSecret');
    const user = jwt.decode(refreshToken);
    const jwtToken = jwt.sign(user, 'jwtSecret', { expiresIn: '1h' });
    res.json({ token: jwtToken });
  } catch (err) {
    res.status = 401;
    res.json({ message: 'Invalid token' });
  }
});

// 受保护的资源
app.get('/protected', (req, res) => {
  const token = req.header('Authorization').replace('Bearer ', '');
  try {
    const decoded = jwt.verify(token, 'jwtSecret');
    res.json({ userId: decoded.userId });
  } catch (err) {
    res.status = 401;
    res.json({ message: 'Invalid token' });
  }
});

app.listen(3000, () => console.log('Server running on port 3000'));

前端(JavaScript):


// 登录
fetch('/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ username: 'john', password: 'password' })
})
.then(response => response.json())
.then(data => {
  localStorage.setItem('jwt', data.token);
  localStorage.setItem('refreshToken', data.refreshToken);
});

// 刷新令牌
const refreshToken = localStorage.getItem('refreshToken');
fetch('/refresh', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ refreshToken: refreshToken })
})
.then(response => response.json())
.then(data => {
  localStorage.setItem('jwt', data.token);
});

// 请求受保护的资源
const token = localStorage.getItem('jwt');
fetch('/protected', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer ' + token
  }
})
.then(response => response.json())
.then(data => console.log(data));
``

通过上述步骤,你可以构建一个完整的JWT认证系统,实现用户身份验证和授权。希望这篇文章对你有所帮助,更多关于JWT的详细信息和示例代码可以参考[慕课网](https://www.imooc.com/)。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消