RustでArgon2のアルゴリズムを扱うargon2クレートを使ってみる
dsk0425lucky
Dsk blog
今回は実装というよりは使い方や挙動を確認したいと思います。
JWTについては、こちらの記事がわかりやすいかと思います。
Cargo.tomlに以下を追加
[dependencies]
jsonwebtoken = "9.3.0"
serde = {version = "1.0.0", features = ["derive"]}
uuid = {version = "1.8.0", features = ["v4", "serde"]}
chrono = "0.4.37"
インポート
use jsonwebtoken::{
decode,
encode,
Algorithm,
DecodingKey,
EncodingKey,
Header,
Validation,
TokenData
};
use serde::{Serialize, Deserialize};
use uuid::Uuid;
use chrono::{Duration, Utc, DateTime};
Claimsを定義
#[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のインスタンスを作成
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,
};
// ...
エンコード
// ...
// 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()
で使用するシークレットキーをハードコードすることは避け、安全に管理された環境変数から読み込むべきです。
デコード
// ...
// デコード用のキーを作成します(実際のアプリケーションでは、環境変数からキーを取得するのが望ましいです)
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の構造体はこのように定義されています
// TokenData構造体は、デコードされたJWTのヘッダーとクレームを格納します。ヘッダーには使用されたアルゴリズムなどのメタデータが含まれ、クレームにはトークンのペイロード(主張)が含まれます
pub struct TokenData<T> {
pub header: Header,
pub claims: T,
}
token
を出力して、header
とclaims
のデコードされた値をエンコードされる前と同じかを比較
// ...
println!("token = {}", token);
println!("test_claims == decoded_token.claims -> {}", test_claims == decoded_token.claims);
println!("header == decoded_token.header -> {}", header == decoded_token.header);
}
token
出力
token = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJleGFtcGxlQGV4YW1wbGUuY29tIiwic3ViIjoiMjlmZTQwNjQtNTFjNi00Yjc2LWIwMDEtMzhjNGUxZjE2YTU3IiwiYXVkIjoiZXhhbXBsZUBleGFtcGxlLmNvbS90ZXN0IiwiZXhwIjoxNzEzMjA5OTU3LCJpYXQiOjE3MTMyMDYzNTcsImp0aSI6IjE0YmVjMzU4LWM2NDUtNGViNy05NTIyLTdjNTYzNGI5MGI3YyJ9.9nTGY9jJXFMxUUMiZClpKMDFla6pu9qqWyXaCFJVyX0zrsIhs9DPcpl_-8EpmYJLrMpIqLNld8Ai_fdPg_9hwg
header
とclaims
共にエンコードされる前の値と同じという結果になりました。
test_claims == decoded_token.claims -> true
header == decoded_token.header -> true
エンコードされたtokne
の値の確認と、デコードされたheader
とclaims
の値が正しいかを確認できました。
今回はjsonwebtokenの挙動を確認してみました。
docs.rs
Github