OAuth 2.0 和 JWT 授权在 Rust 中的实现:初学者分步指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么 Rust 需要授权?

现代 Web 应用程序很少能脱离身份验证和授权系统。Rust 凭借其高性能和内存安全性,正成为构建高负载服务的热门选择。然而,对于初学者来说,处理 OAuth 2.0 等协议和 JWT 格式可能显得复杂。

在本文中,我们将解析 OAuth 2.0 和 JWT(JSON Web Token)的基本概念,并使用流行的 crate 在 Rust 中实现一个简单的授权系统。您将学习如何保护您的 API 端点以及如何处理访问令牌。



什么是 OAuth 2.0 和 JWT?

在编写代码之前,理解理论很重要。



OAuth 2.0:委托访问协议

OAuth 2.0 是一种协议,允许应用程序在不传递用户登录名和密码的情况下,获得对用户资源的有限访问权限。想象一下,您想通过 Google 或 GitHub 登录网站——这就是 OAuth 2.0。

协议的主要参与者:

  • 资源所有者 — 拥有数据的用户。
  • 客户端 — 您的 Rust 应用程序,想要获取访问权限。
  • 授权服务器 — 颁发令牌的服务器(例如 Google)。
  • 资源服务器 — 提供数据的 API(例如 Google Drive)。


JWT:紧凑的令牌格式

JWT(JSON Web Token)是一种用于创建访问令牌的开放标准。令牌由三部分组成,用点分隔:

  • 头部 — 令牌类型和签名算法。
  • 负载 — 数据(声明),例如用户 ID 或角色。
  • 签名 — 确保令牌未被篡改的签名。

JWT 示例:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNrxP0G7n9G4W7N8Y7J8

JWT 的便利之处在于它不需要在服务器上存储会话——所有信息都已嵌入令牌中。



为授权设置 Rust 项目

我们将使用 Actix Web 框架和几个辅助 crate。创建一个新项目:

cargo new rust-auth-examplecd rust-auth-example


在 Cargo.toml 中添加依赖项:

[dependencies]actix-web = "4"actix-rt = "2"serde = { version = "1", features = ["derive"] }serde_json = "1"jsonwebtoken = "9"chrono = { version = "0.4", features = ["serde"] }dotenv = "0.15"env_logger = "0.10"bcrypt = "0.15"


文件结构

为了方便,我们将创建一个模块化结构:

src/├── main.rs├── auth.rs├── models.rs└── handlers.rs


在 .env 中写入 JWT 的密钥:

JWT_SECRET=supersecretkey12345DATABASE_URL=sqlite://users.db


在 Rust 中实现 JWT:从生成到验证

从负责处理 JWT 的 auth.rs 模块开始。



JWT 的结构体

// auth.rsuse serde::{Deserialize, Serialize};use jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};use chrono::{Utc, Duration};

#[derive(Debug, Serialize, Deserialize)]pub struct Claims { pub sub: String, // 用户 ID pub exp: usize, // 过期时间 pub iat: usize, // 签发时间}

pub fn create_jwt(user_id: &str, secret: &str) -> Result<String, jsonwebtoken::errors::Error> { let now = Utc::now(); let expiration = now + Duration::hours(24); // 令牌有效期为 24 小时

let claims = Claims { sub: user_id.to_owned(), exp: expiration.timestamp() as usize, iat: now.timestamp() as usize, };

let token = encode( &Header::default(), &claims,\

博客

书籍推荐