Uncategorized

RustでJSON Web Tokens(JWT)を扱うjsonwebtokenクレートを使ってみる ①

dsk0425lucky

今回は実装というよりは使い方や挙動を確認したいと思います。

JWTとは

JWTについては、こちらの記事がわかりやすいかと思います。

jsonwebtokenを使ってみる

Cargo.tomlに以下を追加

Rust
[dependencies]
jsonwebtoken = "9.3.0"
serde = {version = "1.0.0", features = ["derive"]}
uuid = {version = "1.8.0", features = ["v4", "serde"]}
chrono  = "0.4.37"

インポート

Rust
use jsonwebtoken::{
    decode,
    encode,
    Algorithm,
    DecodingKey,
    EncodingKey,
    Header,
    Validation,
    TokenData
};
use serde::{Serialize, Deserialize};
use uuid::Uuid;
use chrono::{Duration, Utc, DateTime};

Claimsを定義

Rust
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
struct Claims {
    iss: String, // issuer (JWTの発行者)
    sub: Uuid, // subject (ユーザーの識別子)
    aud: String, // audience (JWTの受信者)
    exp: i64, // expiration time (トークンの有効期限)
    iat: i64, // Issued At (発行日時)
    jti: Uuid, // JWT ID (JWTの一意な識別子)
}

Claimsのインスタンスを作成

Rust
fn main() {
    let current_time: DateTime<Utc> = Utc::now();
    let duration_time: DateTime<Utc> = current_time + Duration::hours(1);
    let expiration_time: i64 = duration_time.timestamp(); // 有効期限のUNIX時間
    let issued_at: i64 = current_time.timestamp(); // 発行日時のUNIX時間
    let user_id: Uuid = Uuid::new_v4();
    let jwt_id: Uuid = Uuid::new_v4();

    let test_claims: Claims = Claims {
        iss: "example@example.com".to_string(),
        sub: user_id,
        aud: "example@example.com/test".to_string(),
        exp: expiration_time,
        iat: issued_at,
        jti: jwt_id,
    };
    // ...

エンコード

Rust
	// ...
	// JWTヘッダー作成(HS512を使用します)
    let header: Header = Header::new(Algorithm::HS512); 
    // エンコード用のキーを作成します(実際のアプリケーションでは、環境変数からキーを取得するのが望ましいです)
    let encoding_key: EncodingKey = EncodingKey::from_secret("test_key_generate".as_ref());
    // エンコード
    let token: String = encode(&header, &test_claims, &encoding_key).unwrap();
	// ...

実際のアプリケーションでは、from_secret() で使用するシークレットキーをハードコードすることは避け、安全に管理された環境変数から読み込むべきです。

デコード

Rust
	// ...
	// デコード用のキーを作成します(実際のアプリケーションでは、環境変数からキーを取得するのが望ましいです)
    let decoding_key: DecodingKey = DecodingKey::from_secret("test_key_generate".as_ref());
    // デコードした後に適用される検証の設定
    let mut validation: Validation = Validation::new(Algorithm::HS512);
    validation.set_audience(&["example@example.com/test"]);
    validation.set_issuer(&["example@example.com"]);
    // subがJWTのsubクレームと一致することを検証
    validation.sub = Some(user_id.to_string());
    // デコード
    let decoded_token: TokenData<Claims> = decode::<Claims>(&token, &decoding_key, &validation).unwrap();
    // ...

TokenDataの構造体はこのように定義されています

Rust
// TokenData構造体は、デコードされたJWTのヘッダーとクレームを格納します。ヘッダーには使用されたアルゴリズムなどのメタデータが含まれ、クレームにはトークンのペイロード(主張)が含まれます
pub struct TokenData<T> {
    pub header: Header,
    pub claims: T,
}

tokenを出力して、headerclaimsのデコードされた値をエンコードされる前と同じかを比較

Rust
	// ...
	println!("token = {}", token);
    println!("test_claims == decoded_token.claims -> {}", test_claims == decoded_token.claims);
    println!("header == decoded_token.header -> {}", header == decoded_token.header);
}

token出力

Zsh
token = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJleGFtcGxlQGV4YW1wbGUuY29tIiwic3ViIjoiMjlmZTQwNjQtNTFjNi00Yjc2LWIwMDEtMzhjNGUxZjE2YTU3IiwiYXVkIjoiZXhhbXBsZUBleGFtcGxlLmNvbS90ZXN0IiwiZXhwIjoxNzEzMjA5OTU3LCJpYXQiOjE3MTMyMDYzNTcsImp0aSI6IjE0YmVjMzU4LWM2NDUtNGViNy05NTIyLTdjNTYzNGI5MGI3YyJ9.9nTGY9jJXFMxUUMiZClpKMDFla6pu9qqWyXaCFJVyX0zrsIhs9DPcpl_-8EpmYJLrMpIqLNld8Ai_fdPg_9hwg

headerclaims共にエンコードされる前の値と同じという結果になりました。

Zsh
test_claims == decoded_token.claims -> true
header == decoded_token.header -> true

エンコードされたtokneの値の確認と、デコードされたheaderclaimsの値が正しいかを確認できました。

今回はjsonwebtokenの挙動を確認してみました。

docs.rs

Github

前回の記事
初めての投稿
初めての投稿

ABOUT ME
Dsk
Dsk
Rustのプログラミング言語を学習しています。 わからないことなど多々ありますので、ご指摘いただけますと幸いです
記事URLをコピーしました