salvo-session
Implement session management for user state persistence. Use for login systems, shopping carts, and user preferences.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Implement session management for user state persistence. Use for login systems, shopping carts, and user preferences.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Guide for using RBatis v4 Rust ORM framework. Use when implementing database CRUD operations, writing dynamic SQL with py_sql or html_sql macros, configuring database connections, managing transactions, implementing interceptors, syncing table structures, or integrating RBatis into Genies microservices. Also use when the user asks about RBatis usage patterns, query building, or database operations in Rust.
Genies 前后端接口规范。Use when designing API contracts, defining field naming conventions, date/time formats, response models, pagination, error handling, or ID strategies between Genies backend and frontend (Web/Android/OHOS).
Guide for using flyway-rs database migration framework with RBatis. Use when implementing database schema migrations, managing SQL changelog files, configuring migration runners, handling multi-database migrations, or integrating database versioning into Genies microservices.
Guide for developing Rust microservices using Genies framework following Java DDD layering principles. Use when creating new microservices, designing aggregate roots, implementing domain events, organizing service layers, setting up Flyway migrations, or structuring a DDD-based Genies project.
Genies framework unified skill hub. Use when you need to find the right skill for any Genies framework task, including authentication, authorization, caching, configuration, database, DDD microservices, Dapr messaging, macros, K8s deployment, testing, API conventions, gateway proxy, or Salvo web framework features. Also use when the user asks about Genies framework capabilities, asks which skill to use, or wants a quick overview of available Genies skills.
Guide for using the Genies Rust microservice framework with DDD and Dapr. Use when developing with Genies, creating aggregates, domain events, Dapr subscriptions, Casbin field-level permissions, configuration management, or when the user asks about Genies framework usage patterns.
| name | salvo-session |
| description | Implement session management for user state persistence. Use for login systems, shopping carts, and user preferences. |
| version | 0.89.3 |
| tags | ["security","session","cookie","login"] |
This skill helps implement session management in Salvo applications.
[dependencies]
salvo = { version = "0.89.3", features = ["session"] }
use salvo::prelude::*;
use salvo::session::{CookieStore, Session, SessionDepotExt, SessionHandler};
#[tokio::main]
async fn main() {
let session_handler = SessionHandler::builder(
CookieStore::new(),
b"secretabsecretabsecretabsecretabsecretabsecretabsecretabsecretab",
)
.build()
.unwrap();
let router = Router::new()
.hoop(session_handler)
.get(home)
.push(Router::with_path("login").get(login).post(login))
.push(Router::with_path("logout").get(logout));
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
use salvo::session::{Session, SessionDepotExt};
#[handler]
async fn login(req: &mut Request, depot: &mut Depot, res: &mut Response) {
if req.method() == salvo::http::Method::POST {
let username = req.form::<String>("username").await.unwrap();
let mut session = Session::new();
session.insert("username", username).unwrap();
session.insert("logged_in", true).unwrap();
depot.set_session(session);
res.render(Redirect::other("/"));
} else {
res.render(Text::Html(LOGIN_FORM));
}
}
#[handler]
async fn home(depot: &mut Depot, res: &mut Response) {
if let Some(session) = depot.session_mut() {
if let Some(username) = session.get::<String>("username") {
res.render(Text::Html(format!("Hello, {}!", username)));
return;
}
}
res.render(Text::Html("Please login"));
}
#[handler]
async fn update_preferences(depot: &mut Depot, res: &mut Response) {
if let Some(session) = depot.session_mut() {
session.insert("theme", "dark").unwrap();
let visits: i32 = session.get("visits").unwrap_or(0);
session.insert("visits", visits + 1).unwrap();
}
res.render("Preferences updated");
}
#[handler]
async fn logout(depot: &mut Depot, res: &mut Response) {
if let Some(session) = depot.session_mut() {
session.remove("username");
}
res.render(Redirect::other("/"));
}
use salvo::session::CookieStore;
let session_handler = SessionHandler::builder(
CookieStore::new(),
b"secretabsecretabsecretabsecretabsecretabsecretabsecretabsecretab",
)
.build()
.unwrap();
use salvo::session::MemoryStore;
let session_handler = SessionHandler::builder(
MemoryStore::new(),
b"secretabsecretabsecretabsecretabsecretabsecretabsecretabsecretab",
)
.build()
.unwrap();
use std::time::Duration;
use salvo::session::{CookieStore, SessionHandler};
let session_handler = SessionHandler::builder(
CookieStore::new(),
b"secretabsecretabsecretabsecretabsecretabsecretabsecretabsecretab",
)
.session_ttl(Some(Duration::from_secs(3600)))
.cookie_name("session_id")
.cookie_path("/")
.cookie_secure(true)
.cookie_http_only(true)
.cookie_same_site(salvo::http::cookie::SameSite::Strict)
.build()
.unwrap();
use salvo::prelude::*;
use salvo::session::{CookieStore, Session, SessionDepotExt, SessionHandler};
#[handler]
async fn home(depot: &mut Depot, res: &mut Response) {
let content = if let Some(session) = depot.session_mut()
&& let Some(username) = session.get::<String>("username")
{
format!(r#"<h1>Welcome, {username}!</h1><p><a href="/logout">Logout</a></p>"#)
} else {
r#"<h1>Welcome, Guest!</h1><p><a href="/login">Login</a></p>"#.to_string()
};
res.render(Text::Html(content));
}
#[handler]
async fn login(req: &mut Request, depot: &mut Depot, res: &mut Response) {
if req.method() == salvo::http::Method::POST {
let username = req.form::<String>("username").await.unwrap_or_default();
let password = req.form::<String>("password").await.unwrap_or_default();
if username == "admin" && password == "password" {
let mut session = Session::new();
session.insert("username", username).unwrap();
session.insert("role", "admin").unwrap();
depot.set_session(session);
res.render(Redirect::other("/"));
} else {
res.render(Text::Html("Invalid credentials. <a href='/login'>Try again</a>"));
}
} else {
res.render(Text::Html(r#"
<h1>Login</h1>
<form method="post">
<p><input type="text" name="username" placeholder="Username" /></p>
<p><input type="password" name="password" placeholder="Password" /></p>
<button type="submit">Login</button>
</form>
"#));
}
}
#[handler]
async fn logout(depot: &mut Depot, res: &mut Response) {
if let Some(session) = depot.session_mut() {
session.remove("username");
session.remove("role");
}
res.render(Redirect::other("/"));
}
#[tokio::main]
async fn main() {
let session_handler = SessionHandler::builder(
CookieStore::new(),
b"secretabsecretabsecretabsecretabsecretabsecretabsecretabsecretab",
)
.build()
.unwrap();
let router = Router::new()
.hoop(session_handler)
.get(home)
.push(Router::with_path("login").get(login).post(login))
.push(Router::with_path("logout").get(logout));
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
#[handler]
async fn require_login(
depot: &mut Depot,
res: &mut Response,
ctrl: &mut FlowCtrl,
) {
let logged_in = depot
.session_mut()
.and_then(|s| s.get::<bool>("logged_in"))
.unwrap_or(false);
if !logged_in {
res.render(Redirect::other("/login"));
ctrl.skip_rest();
}
}
#[handler]
async fn require_admin(
depot: &mut Depot,
res: &mut Response,
ctrl: &mut FlowCtrl,
) {
let is_admin = depot
.session_mut()
.and_then(|s| s.get::<String>("role"))
.map(|r| r == "admin")
.unwrap_or(false);
if !is_admin {
res.status_code(StatusCode::FORBIDDEN);
res.render("Admin access required");
ctrl.skip_rest();
}
}