Contents
Axumにおける認証ミドルウェアの概要
Axumフレームワークで非同期ミドルウェアを用いた認証処理は、Webアプリケーションのセキュリティとパフォーマンスの両立に不可欠です。本記事では、Rust言語で構築されたAxumにおいてasync/awaitによる非同期認証ミドルウェアをステップバイステップで実装する方法を解説します。最終的な目標は、JWTトークンの検証ロジックを含むミドルウェアを作成し、ルーターに適用することです。
Axumプロジェクトの初期設定方法
Axumベースのプロジェクトを始めるには、Cargo.tomlの構成とディレクトリ構造の設計が重要です。以下に具体的な手順を示します。
Cargo.tomlの構成例
Axumと関連するライブラリを依存関係として追加します。
|
1 2 3 4 5 |
[dependencies] axum = "0.6" tokio = { version = "1", features = ["full"] } jsonwebtoken = "8.2" |
基本的なディレクトリ構造
以下のような構成が一般的です。各ファイルの役割を明確にすることで、後の開発がスムーズになります。
|
1 2 3 4 5 6 7 |
src/ ├── main.rs ├── middleware/ │ └── auth.rs └── handlers/ └── user.rs |
async/awaitによる非同期処理の基礎
Axumは非同期処理を効率的に扱えるよう設計されています。async fnとawaitキーワードを使うことで、I/O待ち時間を最小限に抑えつつ高パフォーマンスなコードが実現可能です。
Futureトレイトの概要
Rustでは非同期処理を表すためにFutureトレイトを使用します。このトレイトはOutput型を返すpollメソッドを持ち、タスクの完了状態を判定します。
非同期処理の実行フロー
以下にasync/awaitでの実行フローを示します。
async fnで定義された関数はFutureオブジェクトを返すawaitで非同期操作が完了するまで待機- 完了後、
Output型の結果を取得
この仕組みにより、リクエスト処理中に他のタスクを並列実行できるため、スケーラビリティが向上します。
認証ミドルウェアの基本構造設計
Axumで認証ミドルウェアを実装するには、Middlewareトレイトを実装した構造体を作成します。このミドルウェアは、リクエストを受け取り、処理を続けるか中止するかを決定します。
Middleware traitの正しい実装例
Axumではaxum::middleware::Middlewareトレイトを使用します。以下のコードが正しい実装です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
use axum::{ middleware::{self, Next}, Request, Response, }; use std::future::Future; use std::pin::Pin; pub struct AuthMiddleware; impl<B> middleware::Middleware for AuthMiddleware { fn call(&self, req: Request<B>, next: Next<B>) -> Pin<Box<dyn Future<Output = Result<Response, std::convert::Infallible>>>> { let future = async move { // 仮の処理 Ok(next.run(req).await) }; Box::pin(future) } } |
リクエスト処理フローの設計
- ミドルウェアがリクエストを受ける
- 認証処理(例: JWTトークンの検証)
- 成功時:次のハンドラーに処理を引き渡す
- 失敗時:認証失敗レスポンスを返却
このフローにより、セキュリティとパフォーマンスの両立が可能になります。
JWTトークン検証ロジックの実装例
JWT(JSON Web Token)は、ユーザー認証に広く利用される形式です。AxumでJWTを扱うにはjsonwebtokenライブラリが便利です。
Claims型の定義
以下のようにClaims構造体を定義します。
|
1 2 3 4 5 6 7 8 9 |
use jsonwebtoken::{decode, Validation}; use serde::Deserialize; #[derive(Deserialize)] struct Claims { sub: String, exp: usize, } |
セキュリティ設定の定義
まずはハッシュアルゴリズムとシークレットキーを定義します。
|
1 2 3 4 5 6 7 8 9 |
use jsonwebtoken::{Algorithm, Validation}; const JWT_SECRET: &[u8] = b"your-secret-key"; const ALGORITHM: Algorithm = Algorithm::HS256; fn get_validation() -> Validation { Validation::new(ALGORITHM) } |
トークン解析処理のステップ
- リクエストヘッダから
Authorizationフィールドを取得 Bearerで始まる場合、トークン部分を切り出すjsonwebtokenライブラリを使って署名検証と有効期限チェックを行う
以下に簡略版の実装例を示します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
use jsonwebtoken::{decode, DecodingKey, Validation}; pub async fn verify_token(token: &str) -> Result<(), String> { let token_data = decode::<Claims>( token, &DecodingKey::from_secret(JWT_SECRET), &get_validation(), ).map_err(|e| e.to_string())?; // 有効期限のチェックはトークンに含まれる`exp`フィールドで自動的に行われる Ok(()) } |
ミドルウェアとルーターの連携方法
Axumでは、Router::layer()メソッドを使ってミドルウェアを適用できます。特定のエンドポイントにのみ適用するには、ネスト構造や属性フィルタリングを活用します。
Router::layer()の使用例
以下のコードで認証ミドルウェアを全体に適用します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
use axum::{routing::get, Router}; async fn user_route() -> String { "Protected Resource".to_string() } #[tokio::main] async fn main() { let app = Router::new() .route("/user", get(user_route)) .layer(AuthMiddleware); axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) .serve(app.into_make_service()) .await .unwrap(); } |
認証対象ルートの指定方法
特定のエンドポイントにのみミドルウェアを適用するには、Router::route()でネストします。
|
1 2 3 4 5 6 7 8 |
let protected_router = Router::new() .route("/user", get(user_route)) .layer(AuthMiddleware); let app = Router::new() .nest("/api", protected_router) .route("/", get(index)); |
エラーハンドリングのベストプラクティス
認証ミドルウェアでは、エラー発生時の処理が重要です。Result型を適切に扱い、ユーザーにわかりやすいステータスコードを返却する必要があります。
Result型の扱い方
Axumのハンドラ関数ではResult型を使用します。成功時はOk(Response)、失敗時はErr(Status)で応答します。
|
1 2 3 4 5 6 7 8 9 10 11 |
use axum::response::{IntoResponse, Response}; use std::convert::Infallible; pub async fn auth_middleware(req: Request<B>) -> Result<Response, Infallible> { // 認証処理 if let Err(e) = verify_token(...) { return Ok(axum::http::StatusCode::UNAUTHORIZED.into_response()); } Ok(next.run(req).await) } |
ステータスコードの振り分け戦略
| エラー種別 | ステータスコード | 説明 |
|---|---|---|
| 認証失敗 | 401 |
トークンが無効または期限切れ |
| プレミアム機能 | 403 |
アクセス権限がない |
| 不明なエラー | 500 |
内部サーバーエラー |
ステータスコードの振り分けは、ユーザーに適切なフィードバックを提供するため重要です。
まとめ
本記事では、Axumフレームワークにおける非同期認証ミドルウェアの実装方法について以下の点を解説しました。
- Axumプロジェクトの初期設定とディレクトリ構造の設計
async/awaitによる非同期処理の仕組みと実装例- 認証ミドルウェアの基本構造と
Middleware traitの使用方法 - JWTトークン検証ロジックのステップバイステップな実装
- ミドルウェアをルーターに適用する
Router::layer()の活用法 - エラーハンドリングにおけるベストプラクティス
本記事を参考にAxumプロジェクトで認証ミドルウェアを実装してみましょう。