| Crates.io | r-token |
| lib.rs | r-token |
| version | 1.2.0 |
| created_at | 2026-01-04 13:52:49.020594+00 |
| updated_at | 2026-01-19 11:31:29.05949+00 |
| description | A simple and efficient token generation library for Rust, ideal for API authentication and session management. |
| homepage | https://github.com/KayanoLiam/r-token |
| repository | https://github.com/KayanoLiam/r-token.git |
| max_upload_size | |
| id | 2021894 |
| size | 257,614 |
README: 日本語(このページ) | English
r-token は Rust の token 認証ヘルパーです。actix-web と axum の両方で、handler の引数に extractor(RUser / RRedisUser)を書くだけで認証済みコンテキストを取得できます。
この crate が提供するのは「認証(authentication)」のための primitives です:
バックエンドは 2 種類です:
RTokenManager(期限は「Unix epoch ミリ秒」の絶対時刻で追跡)RTokenRedisManager(期限は Redis TTL(秒)で強制)RUser / RRedisUser を引数に書くだけでルートを保護TokenSourceConfig で制御rbac feature)redis crate)| 目的 | in-memory | Redis/Valkey |
|---|---|---|
| actix-web extractor | RUser |
RRedisUser(redis-actix) |
| axum extractor | RUser |
RRedisUser(redis-axum) |
| TTL / 期限切れ | アプリ側(期限 ms を検証時に掃除) | Redis 側(TTL 秒で削除) |
| roles(RBAC) | rbac feature |
rbac feature(value は JSON) |
Secure / HttpOnly / SameSite を検討してください(サンプルは簡潔さ優先で HttpOnly のみ)。user_id(RBAC 有効時は JSON)を保存します。Redis の漏えいを前提にする場合は、token を hash 化して key として保存する方式を検討してください(現状この crate では未実装)。[dependencies]
r-token = "1.2.0"
MSRV(最小 Rust バージョン)は Cargo.toml の rust-version を参照してください。
依存を任意化するため、機能は Cargo features で切り替えます:
actix(デフォルト): actix-web 連携(RUser / RRedisUser の actix extractor)axum: axum 連携(RUser / RRedisUser の axum extractor、Tokio が必要)redis: Redis/Valkey バックエンド(Tokio が必要)redis-actix: 便利 feature(redis + actix)redis-axum: 便利 feature(redis + axum)rbac: roles を含む RBAC サポート(Serde が必要)例:
[dependencies]
r-token = { version = "1.2.0", default-features = false, features = ["actix"] }
[dependencies]
r-token = { version = "1.2.0", default-features = false, features = ["axum"] }
[dependencies]
r-token = { version = "1.2.0", features = ["redis-actix"] }
[dependencies]
r-token = { version = "1.2.0", features = ["redis-axum", "rbac"] }
r-token = "1.2.0"(デフォルト actix)default-features = false, features = ["axum"]features = ["redis-actix"]features = ["redis-axum"]rbac を追加一般的な API の流れは次の通りです:
/login(公開)で login(..) を呼び、token を返す(必要なら cookie もセット)Authorization: <token>Authorization: Bearer <token>r_token)RUser / RRedisUser を引数として書くuser.id(RBAC 有効なら user.roles)が使える既定では Authorization header と cookie から token を探します。
対応する header 形式:
Authorization: <token>
Authorization: Bearer <token>
cookie は r_token(既定)を探索します。探索ルールは TokenSourceConfig で変更できます:
header_names: 順に探す header 名(例:Authorization、X-Api-Token)cookie_names: 順に探す cookie 名(例:r_token)priority: HeaderFirst / CookieFirstactix-web では app_data(web::Data<TokenSourceConfig>)、axum では Extension(TokenSourceConfig) で注入します。
[dependencies]
r-token = "1.2.0"
保護したい handler に RUser を引数として追加します(手動パース不要)。
use actix_web::{get, post, web, HttpResponse, Responder};
use r_token::{RTokenError, RTokenManager, RUser};
#[post("/login")]
async fn login(
manager: web::Data<RTokenManager>,
body: String,
) -> Result<impl Responder, RTokenError> {
let user_id = body.trim();
let token = manager.login(user_id, 3600)?;
Ok(HttpResponse::Ok().body(token))
}
#[get("/profile")]
async fn profile(user: RUser) -> impl Responder {
format!("Profile: {}", user.id)
}
#[post("/logout")]
async fn logout(
manager: web::Data<RTokenManager>,
user: RUser,
) -> Result<impl Responder, RTokenError> {
manager.logout(&user.token)?;
Ok(HttpResponse::Ok().body("Logged out"))
}
use actix_web::{web, App, HttpServer};
use r_token::RTokenManager;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let manager = RTokenManager::new();
HttpServer::new(move || App::new().app_data(web::Data::new(manager.clone())))
.bind(("127.0.0.1", 8080))?
.run()
.await
}
token=$(curl -s -X POST http://127.0.0.1:8080/login -d "alice")
curl -s -H "Authorization: $token" http://127.0.0.1:8080/profile
curl -s -X POST -H "Authorization: $token" http://127.0.0.1:8080/logout
[dependencies]
r-token = { version = "1.2.0", default-features = false, features = ["axum"] }
tokio = { version = "1", features = ["macros", "net", "rt-multi-thread"] }
Extension で manager を注入します。RUser は handler 引数としてそのまま使えます。
use axum::{
Router,
extract::Extension,
http::{HeaderValue, StatusCode, header},
response::{IntoResponse, Response},
routing::{get, post},
};
use r_token::{RTokenError, RTokenManager, RUser, TOKEN_COOKIE_NAME};
async fn login(Extension(manager): Extension<RTokenManager>, body: String) -> Result<Response, Response> {
let user_id = body.trim();
if user_id.is_empty() {
return Err((StatusCode::BAD_REQUEST, "Empty user id").into_response());
}
let token = manager.login(user_id, 3600).map_err(|e: RTokenError| e.into_response())?;
let mut resp = token.clone().into_response();
let cookie = format!("{}={}; Path=/; HttpOnly", TOKEN_COOKIE_NAME, token);
let cookie = HeaderValue::from_str(&cookie)
.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Invalid cookie").into_response())?;
resp.headers_mut().insert(header::SET_COOKIE, cookie);
Ok(resp)
}
async fn profile(user: RUser) -> impl IntoResponse {
format!("Profile: {}", user.id)
}
async fn logout(Extension(manager): Extension<RTokenManager>, user: RUser) -> Result<&'static str, RTokenError> {
manager.logout(&user.token)?;
Ok("Logged out")
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let manager = RTokenManager::new();
let app = Router::new()
.route("/login", post(login))
.route("/profile", get(profile))
.route("/logout", post(logout))
.layer(Extension(manager));
let listener = tokio::net::TcpListener::bind("127.0.0.1:8082").await?;
axum::serve(listener, app).await?;
Ok(())
}
token=$(curl -s -X POST http://127.0.0.1:8082/login -d "alice")
curl -s -H "Authorization: $token" http://127.0.0.1:8082/profile
curl -s -X POST -H "Authorization: $token" http://127.0.0.1:8082/logout
RTokenRedisManager は非同期 API です(Tokio runtime が必要)。actix-web / axum のどちらでも、RRedisUser extractor が利用できます(redis + actix または axum)。
use r_token::RTokenRedisManager;
let redis_url = "redis://127.0.0.1/";
let prefix = "r_token:token:";
let manager = RTokenRedisManager::connect(redis_url, prefix).await?;
prefix は環境ごと・アプリごとの分離に使います。末尾の : は自動で補われます。
web::Data<RTokenRedisManager> として注入しますRRedisUser を引数に持ちますサンプル実装は redis_main.rs を参照してください。
Extension(RTokenRedisManager) として注入しますRRedisUser を引数に持ちますサンプル実装は redis_axum_main.rs を参照してください。
rbac feature を有効にすると、token に roles を紐づけられます。
利用できる主な API:
RTokenManager::login_with_roles(user_id, ttl, roles)RTokenManager::set_roles(token, roles)(冪等)RTokenManager::get_roles(token)RUser.roles / RUser::has_role(..)RTokenRedisManager::login_with_roles(user_id, ttl, roles)RTokenRedisManager::set_roles(token, roles)(冪等、TTL を保持)RTokenRedisManager::get_roles(token)RTokenRedisManager::validate_with_roles(token)RRedisUser.rolesr-token は「認証」までを担当します。認可(特定の role が必要、など)はアプリ側で実装します。
actix-web:
use actix_web::{get, HttpResponse};
use r_token::RUser;
#[get("/admin")]
async fn admin(user: RUser) -> HttpResponse {
if !user.has_role("admin") {
return HttpResponse::Forbidden().body("forbidden");
}
HttpResponse::Ok().body("ok")
}
expires_at(token) -> Option<u64>: 保存されている期限(ms)。期限切れ判定はしないttl_seconds(token) -> Option<i64>: 残り TTL(秒)。期限切れは Some(0)renew(token, ttl) -> bool: 期限を延長(期限切れは削除して false)rotate(token, ttl) -> Option<String>: 新 token を発行し old token を失効prune_expired() -> usize: 期限切れ token を掃除(件数を返す)ttl_seconds(token) -> Option<i64>: Redis TTL の意味をそのまま返す
None: key が存在しないSome(-1): key は存在するが期限がないSome(n)(n >= 0): 残り TTL(秒)renew(token, ttl) -> bool: EXPIRE による延長rotate(token, ttl) -> Option<String>: 新 token を発行して old key を削除(簡潔さ優先のため原子的ではない)RTokenErrorRTokenManager が返すエラーは現在 MutexPoisoned のみです。
actix_web::ResponseError を実装しているため handler からそのまま返せますIntoResponse を実装しており、既定では 500 を返します(詳細は Display の文字列)共通の失敗パターン:
in-memory(actix-web、8080):
cargo run --bin r-token
Redis/Valkey(actix-web、8081):
REDIS_URL=redis://127.0.0.1/ R_TOKEN_PREFIX=r_token:token: \
cargo run --bin r-token-redis --features redis-actix
in-memory(axum、8082):
cargo run --bin r-token-axum --features axum
Redis/Valkey(axum、8083):
REDIS_URL=redis://127.0.0.1/ R_TOKEN_PREFIX=r_token:token: \
cargo run --bin r-token-redis-axum --features redis-axum
基本:
cargo test
全 feature:
cargo test --all-features
Redis テストについて:
REDIS_URL が指定されていない場合、テストは redis-server をローカルで起動しようとします。redis-server が利用できない環境では、REDIS_URL を設定して既存の Redis/Valkey を使ってください。Authorization / cookie のどちらも無い)Authorization の形式が違う(Bearer を付ける/付けないはどちらも可)TokenSourceConfig を変更していて header/cookie 名が一致していないweb::Data<RTokenManager> / web::Data<RTokenRedisManager> を app_data に入れ忘れているExtension(RTokenManager) / Extension(RTokenRedisManager) を .layer(..) していないMIT