r-token
README: 日本語(このページ) | English
r-token は Rust の token 認証ヘルパーです。actix-web と axum の両方で、handler の引数に extractor(RUser / RRedisUser)を書くだけで認証済みコンテキストを取得できます。
この crate が提供するのは「認証(authentication)」のための primitives です:
- token の発行(login)
- token の検証(extractor / validate)
- token の失効(logout)
- TTL による自動失効(in-memory / Redis)
- 任意で roles を付与(RBAC)
バックエンドは 2 種類です:
- インメモリ:
RTokenManager(期限は「Unix epoch ミリ秒」の絶対時刻で追跡) - Redis/Valkey(任意):
RTokenRedisManager(期限は Redis TTL(秒)で強制)
目次
- 特長
- 対応マトリクス
- セキュリティ注意
- インストール
- Feature flags
- まず何を選べばいい?(早見表)
- 認証の基本フロー
- Token の取得元(Header / Cookie)
- Quickstart:actix-web(in-memory)
- Quickstart:axum(in-memory)
- Redis/Valkey バックエンド
- RBAC(roles)
- TTL 操作(renew / rotate / ttl_seconds など)
- エラーとステータスコード
- 例:このリポジトリのサンプルサーバー
- テスト
- FAQ / トラブルシュート
- ライセンス
特長
- Extractor-first:
RUser/RRedisUserを引数に書くだけでルートを保護 - 最小のボイラープレート: header/cookie パース用の独自ミドルウェアが不要
- TTL 対応: インメモリ TTL と Redis TTL の両方をサポート
- Token source 設定: header/cookie 名と優先順位を
TokenSourceConfigで制御 - RBAC(任意): roles の付与と検証(
rbacfeature) - Valkey 対応: Redis 互換プロトコルなら同様に利用可能(接続は
rediscrate)
対応マトリクス
| 目的 | 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) |
セキュリティ注意
- bearer-token 認証です。本番では必ず HTTPS を使ってください。
- token 文字列はアクセス権そのものです。ログ出力しない/クライアントに平文保存しないなど、パスワード同様に扱ってください。
- cookie で運ぶ場合は、基本的に
Secure/HttpOnly/SameSiteを検討してください(サンプルは簡潔さ優先でHttpOnlyのみ)。 - Redis バックエンドは value として
user_id(RBAC 有効時は JSON)を保存します。Redis の漏えいを前提にする場合は、token を hash 化して key として保存する方式を検討してください(現状この crate では未実装)。
インストール
[]
= "1.2.0"
MSRV(最小 Rust バージョン)は Cargo.toml の rust-version を参照してください。
Feature flags
依存を任意化するため、機能は 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 が必要)
例:
[]
= { = "1.2.0", = false, = ["actix"] }
[]
= { = "1.2.0", = false, = ["axum"] }
[]
= { = "1.2.0", = ["redis-actix"] }
[]
= { = "1.2.0", = ["redis-axum", "rbac"] }
まず何を選べばいい?(早見表)
- actix-web + in-memory:
r-token = "1.2.0"(デフォルトactix) - axum + in-memory:
default-features = false, features = ["axum"] - actix-web + Redis/Valkey:
features = ["redis-actix"] - axum + Redis/Valkey:
features = ["redis-axum"] - roles も必要: 上記に
rbacを追加
認証の基本フロー
一般的な API の流れは次の通りです:
/login(公開)でlogin(..)を呼び、token を返す(必要なら cookie もセット)- クライアントは token を以後のリクエストに付与する
Authorization: <token>Authorization: Bearer <token>- または cookie(既定は
r_token)
- 保護したい handler に
RUser/RRedisUserを引数として書く - extractor が成功すれば、handler 内で
user.id(RBAC 有効ならuser.roles)が使える
Token の取得元(Header / Cookie)
既定では 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 / CookieFirst
actix-web では app_data(web::Data<TokenSourceConfig>)、axum では Extension(TokenSourceConfig) で注入します。
Quickstart:actix-web(in-memory)
1) 依存
[]
= "1.2.0"
2) ルート(login / profile / logout)
保護したい handler に RUser を引数として追加します(手動パース不要)。
use ;
use ;
async
async
async
3) アプリ state(必須)
use ;
use RTokenManager;
async
4) 試す(curl)
token=
Quickstart:axum(in-memory)
1) 依存
[]
= { = "1.2.0", = false, = ["axum"] }
= { = "1", = ["macros", "net", "rt-multi-thread"] }
2) ルート(login / profile / logout)
Extension で manager を注入します。RUser は handler 引数としてそのまま使えます。
use ;
use ;
async
async
async
async
3) 試す(curl)
token=
Redis/Valkey バックエンド
RTokenRedisManager は非同期 API です(Tokio runtime が必要)。actix-web / axum のどちらでも、RRedisUser extractor が利用できます(redis + actix または axum)。
接続
use RTokenRedisManager;
let redis_url = "redis://127.0.0.1/";
let prefix = "r_token:token:";
let manager = connect.await?;
prefix は環境ごと・アプリごとの分離に使います。末尾の : は自動で補われます。
actix-web で使う
- manager は
web::Data<RTokenRedisManager>として注入します - 保護ルートは
RRedisUserを引数に持ちます
サンプル実装は redis_main.rs を参照してください。
axum で使う
- manager は
Extension(RTokenRedisManager)として注入します - 保護ルートは
RRedisUserを引数に持ちます
サンプル実装は redis_axum_main.rs を参照してください。
RBAC(roles)
rbac feature を有効にすると、token に roles を紐づけられます。
利用できる主な API:
- in-memory:
RTokenManager::login_with_roles(user_id, ttl, roles)RTokenManager::set_roles(token, roles)(冪等)RTokenManager::get_roles(token)RUser.roles/RUser::has_role(..)
- Redis:
RTokenRedisManager::login_with_roles(user_id, ttl, roles)RTokenRedisManager::set_roles(token, roles)(冪等、TTL を保持)RTokenRedisManager::get_roles(token)RTokenRedisManager::validate_with_roles(token)RRedisUser.roles
典型的な「認可」パターン
r-token は「認証」までを担当します。認可(特定の role が必要、など)はアプリ側で実装します。
actix-web:
use ;
use RUser;
async
TTL 操作(renew / rotate / ttl_seconds など)
in-memory(RTokenManager)
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 を掃除(件数を返す)
Redis/Valkey(RTokenRedisManager)
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 を削除(簡潔さ優先のため原子的ではない)
エラーとステータスコード
RTokenError
RTokenManager が返すエラーは現在 MutexPoisoned のみです。
- actix-web:
actix_web::ResponseErrorを実装しているため handler からそのまま返せます - axum:
IntoResponseを実装しており、既定では 500 を返します(詳細はDisplayの文字列)
extractor の 401 / 500
共通の失敗パターン:
- 401 Unauthorized: token が無い / 無効 / 期限切れ
- 500 Internal Server Error: manager が state に注入されていない(設定忘れ)、または内部の mutex が poisoned
例:このリポジトリのサンプルサーバー
in-memory(actix-web、8080):
Redis/Valkey(actix-web、8081):
REDIS_URL=redis://127.0.0.1/ R_TOKEN_PREFIX=r_token:token: \
in-memory(axum、8082):
Redis/Valkey(axum、8083):
REDIS_URL=redis://127.0.0.1/ R_TOKEN_PREFIX=r_token:token: \
テスト
基本:
全 feature:
Redis テストについて:
REDIS_URLが指定されていない場合、テストはredis-serverをローカルで起動しようとします。redis-serverが利用できない環境では、REDIS_URLを設定して既存の Redis/Valkey を使ってください。
FAQ / トラブルシュート
401 になる
- token を送っていない(
Authorization/ cookie のどちらも無い) Authorizationの形式が違う(Bearerを付ける/付けないはどちらも可)- token が期限切れ(in-memory では検証時に削除されます。Redis では TTL で消えます)
TokenSourceConfigを変更していて header/cookie 名が一致していない
500 になる(Token manager not found / Redis error)
- actix-web:
web::Data<RTokenManager>/web::Data<RTokenRedisManager>をapp_dataに入れ忘れている - axum:
Extension(RTokenManager)/Extension(RTokenRedisManager)を.layer(..)していない - Redis: 接続先が落ちている、URL が間違っている
ライセンス
MIT