salvo-auth
Implement authentication and authorization using JWT, Basic Auth, or custom schemes. Use for securing API endpoints and user management.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Implement authentication and authorization using JWT, Basic Auth, or custom schemes. Use for securing API endpoints and user management.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
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-auth |
| description | Implement authentication and authorization using JWT, Basic Auth, or custom schemes. Use for securing API endpoints and user management. |
| version | 0.89.3 |
| tags | ["security","authentication","jwt","basic-auth"] |
This skill helps implement authentication and authorization in Salvo applications.
[dependencies]
salvo = { version = "0.89.3", features = ["jwt-auth"] }
jsonwebtoken = "9"
serde = { version = "1", features = ["derive"] }
chrono = "0.4"
use salvo::jwt_auth::{JwtAuth, JwtClaims};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct JwtClaims {
sub: String,
exp: i64,
role: String,
}
const SECRET_KEY: &str = "your-secret-key-at-least-32-bytes";
#[tokio::main]
async fn main() {
let auth_handler = JwtAuth::new("secret_key")
.finders(vec![
Box::new(HeaderFinder::new()),
Box::new(QueryFinder::new("token")),
]);
let router = Router::new()
.push(Router::with_path("login").post(login))
.push(
Router::with_path("protected")
.hoop(auth_handler)
.get(protected_handler)
);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
use jsonwebtoken::{encode, EncodingKey, Header};
use salvo::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct LoginRequest {
username: String,
password: String,
}
#[derive(Serialize)]
struct LoginResponse {
token: String,
}
#[handler]
async fn login(body: JsonBody<LoginRequest>) -> Result<Json<LoginResponse>, StatusError> {
let req = body.into_inner();
if req.username != "admin" || req.password != "password" {
return Err(StatusError::unauthorized());
}
let claims = JwtClaims {
sub: req.username,
exp: (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp(),
role: "user".to_string(),
};
let token = encode(
&Header::default(),
&claims,
&EncodingKey::from_secret(SECRET_KEY.as_bytes()),
)
.map_err(|_| StatusError::internal_server_error())?;
Ok(Json(LoginResponse { token }))
}
use salvo::jwt_auth::JwtAuthDepotExt;
#[handler]
async fn protected_handler(depot: &mut Depot) -> Result<String, StatusError> {
let token_data = depot.jwt_auth_data::<JwtClaims>()
.ok_or_else(|| StatusError::unauthorized())?;
Ok(format!("Hello, {}! Role: {}", token_data.claims.sub, token_data.claims.role))
}
[dependencies]
salvo = { version = "0.89.3", features = ["basic-auth"] }
use salvo::prelude::*;
use salvo::basic_auth::{BasicAuth, BasicAuthValidator};
struct MyValidator;
impl BasicAuthValidator for MyValidator {
async fn validate(&self, username: &str, password: &str, depot: &mut Depot) -> bool {
if username == "admin" && password == "password" {
depot.insert("user_role", "admin");
true
} else if username == "user" && password == "userpass" {
depot.insert("user_role", "user");
true
} else {
false
}
}
}
#[tokio::main]
async fn main() {
let auth_handler = BasicAuth::new(MyValidator);
let router = Router::new()
.push(
Router::with_path("admin")
.hoop(auth_handler)
.get(admin_handler)
);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
use salvo::prelude::*;
#[handler]
async fn auth_middleware(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
let token = req.header::<String>("Authorization")
.and_then(|h| h.strip_prefix("Bearer ").map(String::from));
match token {
Some(token) => {
match validate_token(&token) {
Ok(user_id) => {
depot.insert("user_id", user_id);
ctrl.call_next(req, depot, res).await;
}
Err(_) => {
res.status_code(StatusCode::UNAUTHORIZED);
res.render(Json(serde_json::json!({"error": "Invalid token"})));
ctrl.skip_rest();
}
}
}
None => {
res.status_code(StatusCode::UNAUTHORIZED);
res.render(Json(serde_json::json!({"error": "Missing token"})));
ctrl.skip_rest();
}
}
}
#[handler]
async fn api_key_auth(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
let api_key = req.header::<String>("X-API-Key");
match api_key {
Some(key) if is_valid_api_key(&key) => {
depot.insert("api_key", key);
ctrl.call_next(req, depot, res).await;
}
_ => {
res.status_code(StatusCode::UNAUTHORIZED);
res.render("Invalid API key");
ctrl.skip_rest();
}
}
}
use salvo::prelude::*;
use salvo::session::{SessionHandler, CookieStore, SessionDepotExt};
#[tokio::main]
async fn main() {
let session_handler = SessionHandler::builder(
CookieStore::new(),
b"secret_key_must_be_at_least_64_bytes_long_for_security_reasons!!",
)
.build()
.unwrap();
let router = Router::new()
.hoop(session_handler)
.push(Router::with_path("login").post(login))
.push(Router::with_path("profile").get(profile));
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
#[handler]
async fn login(depot: &mut Depot) -> StatusCode {
let session = depot.session_mut().unwrap();
session.insert("user_id", 123).unwrap();
StatusCode::OK
}
#[handler]
async fn profile(depot: &mut Depot) -> Result<String, StatusError> {
let session = depot.session().unwrap();
let user_id: Option<i64> = session.get("user_id");
match user_id {
Some(id) => Ok(format!("User ID: {}", id)),
None => Err(StatusError::unauthorized()),
}
}
#[derive(Clone)]
enum Role {
Admin,
User,
Guest,
}
fn require_role(required: Role) -> impl Handler {
move |req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl| async move {
let user_role = depot.get::<Role>("user_role");
match user_role {
Some(role) if matches!((role, &required), (Role::Admin, _) | (Role::User, Role::User)) => {
ctrl.call_next(req, depot, res).await;
}
_ => {
res.status_code(StatusCode::FORBIDDEN);
res.render("Insufficient permissions");
ctrl.skip_rest();
}
}
}
}
let router = Router::new()
.push(
Router::with_path("admin")
.hoop(auth_middleware)
.hoop(require_role(Role::Admin))
.get(admin_handler)
);