iT邦幫忙

2023 iThome 鐵人賽

DAY 23
0
Software Development

Rust Web API 從零開始系列 第 23

Day23 - 權限驗證(1) - JWT Handler

  • 分享至 

  • xImage
  •  

到目前為止基礎的功能已經完成了,接下來幾天就要來做一些附加的內容,比如說使用後台API來做管理,所以就來做個登入用的API吧。

JWT權限驗證

關於權限驗證的方案,我打算使用JWT做權限驗證,首先加入套件jsonwebtoken:

cargo add jsonwebtoken

這是rust中比較熱門用來解析jwt的套件,接下來我們需要定義好jwt的格式,所以就先建立一個產生token用的Claims結構:

//// jwt_handler.rs
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    aud: String, // Optional. Audience (who or what the token is intended for)
    exp: usize, // Required (validate_exp defaults to true in validation). Expiration time (as UTC timestamp)
    iat: usize, // Optional. Issued at (as UTC timestamp) (default = now)
    iss: String, // Optional. Issuer (who issued the token)
    nbf: usize, // Optional. Not Before (as UTC timestamp)
    sub: String, // Optional. Subject (whom token refers to)
}

Claims中的欄位不是必須的,但如果有設定的話jsonwebtoken默認會支援,套件本身也可以容許我們自行定義欄位。接下來要建立用於產生token的JwtHandler

//// jwt_handler.rs
#[derive(Clone, Debug)]
pub struct JwtHandler {
    pub private_key: Secret<String>,
    pub header: Header,
    pub public_key: String,
    pub expiration_minutes: i64,
}

如果對於JWT熟悉的話就知道,我們需要自行保管用來簽名的私鑰,這部份就跟前面的資料庫連線一樣我們要從環境變數中取得並用Secret保護,另外我們也可以在設定檔中決定token的過期時間。接下來就是實做簽名跟解析的方法:

impl JwtHandler {
    pub fn create_token(self, user_name: &str) -> String {
        let claims = Claims {
            aud: user_name.to_owned(),
            exp: (Utc::now() + chrono::Duration::minutes(self.expiration_minutes)).timestamp()
                as usize,
            iat: Utc::now().timestamp() as usize,
            iss: "zero_to_production".to_owned(),
            nbf: Utc::now().timestamp() as usize,
            sub: "zero_to_production".to_owned(),
        };

        encode(
            &self.header,
            &claims,
            &EncodingKey::from_secret(self.private_key.expose_secret().as_ref()),
        )
        .unwrap_or_default()
    }

    pub fn decode_token(self, token: String) -> Result<Claims> {
        let mut validation = jsonwebtoken::Validation::new(Algorithm::HS512);
        validation.sub = Some("zero_to_production".to_string());
        decode::<Claims>(
            &token,
            &DecodingKey::from_secret(self.private_key.expose_secret().as_ref()),
            &validation,
        )
        .map(|data| data.claims)
    }
}

簽名的實現非常簡單,只要使用jsonwebtoken提供的encode方法即可,注意一下EncodingKey這個結構其實提供了很多種不同的簽名方式,通常情況下用默認的就可以了。
接下來是解析token的方法,首先建立驗證器後,驗證器會將token解析的結果以Result的方式回傳,除了解析失敗以外,因為我們的claims有設定過期時間,所以解析完畢後發現token過期也會回傳Error


上一篇
Day22 - 訂閱確認,再論SeaORM中的ActiveModel
下一篇
Day24 - 權限驗證(2) - Login API
系列文
Rust Web API 從零開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言