tower-sessions
🥠 作为 `tower` 和 `axum` 中间件的会话管理。
🎨 概述
这个 crate 提供了作为 tower
中间件的会话功能,会话是与网站访问者关联的键值对。
它提供了:
- 可插拔的存储后端: 通过实现
SessionStore
trait 来使用自己的后端,完全解耦会话与其存储。 - 最小开销: 会话只在实际使用时从后端存储加载,且仅在使用它们的处理程序中加载。这意味着这个中间件可以安装在路由图的任何位置,开销最小。
axum
的Session
提取器: 使用axum
构建的应用可以直接在处理程序中使用Session
作为提取器。这使得使用会话变得像在处理程序中包含Session
一样简单。- 简单的键值接口: 会话提供支持原生 Rust 类型的键值接口。只要这些类型是
Serialize
且可以转换为 JSON,插入、获取和删除任何值都很简单。 - 强类型会话: 在这个基础键值接口之上很容易添加强类型保证。
这个 crate 的会话实现受到 Django 会话中间件 的启发,并提供了这些语义的转译。
会话存储
会话数据持久化由实现 SessionStore
的用户提供的类型管理。这意味着应用可以并且应该根据其特定需求实现会话存储。
话虽如此,已经存在一些会话存储实现,可能是有用的起点。
Crate | 持久化 | 描述 |
---|---|---|
tower-sessions-dynamodb-store | 是 | DynamoDB 会话存储 |
tower-sessions-firestore-store | 是 | Firestore 会话存储 |
tower-sessions-libsql-store | 是 | libSQL 会话存储 |
tower-sessions-mongodb-store | 是 | MongoDB 会话存储 |
tower-sessions-moka-store | 否 | Moka 会话存储 |
tower-sessions-redis-store | 是 | 通过 fred 的 Redis 会话存储 |
tower-sessions-rorm-store | 是 | rorm 提供的 SQLite、Postgres 和 MySQL 会话存储 |
tower-sessions-rusqlite-store | 是 | Rusqlite 会话存储 |
tower-sessions-sled-store | 是 | Sled 会话存储 |
tower-sessions-sqlx-store | 是 | SQLite、Postgres 和 MySQL 会话存储 |
tower-sessions-surrealdb-store | 是 | SurrealDB 会话存储 |
有存储要添加吗?请开启一个 PR 来添加它。
用户会话管理
为了便于身份验证和授权,我们在这个 crate 之上构建了 axum-login
。如果你在寻找一个通用的身份验证解决方案,请查看它。
📦 安装
要在你的项目中使用这个 crate,请在你的 Cargo.toml
文件中添加以下内容:
[dependencies]
tower-sessions = "0.12.3"
🤸 使用
axum
示例
use std::net::SocketAddr;
use axum::{response::IntoResponse, routing::get, Router};
use serde::{Deserialize, Serialize};
use time::Duration;
use tower_sessions::{Expiry, MemoryStore, Session, SessionManagerLayer};
const COUNTER_KEY: &str = "counter";
#[derive(Default, Deserialize, Serialize)]
struct Counter(usize);
async fn handler(session: Session) -> impl IntoResponse {
let counter: Counter = session.get(COUNTER_KEY).await.unwrap().unwrap_or_default();
session.insert(COUNTER_KEY, counter.0 + 1).await.unwrap();
format!("当前计数:{}", counter.0)
}
#[tokio::main]
async fn main() {
let session_store = MemoryStore::default();
let session_layer = SessionManagerLayer::new(session_store)
.with_secure(false)
.with_expiry(Expiry::OnInactivity(Duration::seconds(10)));
let app = Router::new().route("/", get(handler)).layer(session_layer);
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}
[!注意] 更多使用信息请参见crate 文档。
🦺 安全性
这个 crate 使用 #![forbid(unsafe_code)]
来确保所有内容都是用 100% 安全的 Rust 实现的。
🛟 获取帮助
我们准备了一些示例来帮助你入门。你也可以开启一个讨论来提出其他问题。
👯 贡献
我们感谢各种形式的贡献,谢谢你!