Как следует применять типы десериализации для jsonwebtokens в ржавчине? - PullRequest
1 голос
/ 10 октября 2019

Ниже приведен инструмент создания токена, который я создал с помощью jsonwebtoken. Я хочу как-то принудительно применить ожидаемый тип токена, чтобы, если я передам строку токена и сообщу ей ожидаемый набор утверждений, он не вернет успешный результат.

Ниже приведены тестовые примеры с комментариями о том, где я думаюэтот сервис должен потерпеть неудачу, и комментарий в коде, где я думаю, что утверждение должно иметь место.

Как я могу применить эти типы утверждений, чтобы быть уверенным, что я получаю желаемый тип токена?

use jwt;
use jwt::{ Header, Validation };
use std::convert::AsRef;
use serde::de::DeserializeOwned;
use serde::Serialize;

#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum TokenType {
    User,
    Reg,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct RegisterClaims {
    typ:TokenType,
    org_name:String,
    name:String,
    email:String,
    exp: usize,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct UserClaims {
    typ:TokenType,
    usr_id:String,
    sub:String,
    exp: usize,
}

#[derive(Debug)]
pub struct InvalidToken {
    cause: String,
}

pub struct TokenFactory {
    secret:String,
}

impl TokenFactory {
    pub fn new(secret:String) -> TokenFactory {
        TokenFactory {
            secret
        }
    }

    pub fn validate<T: DeserializeOwned>(&self, raw_token:String) -> Result<T, InvalidToken> {
        match jwt::decode::<T>(&raw_token, self.secret.as_ref(), &Validation::default()) {
            Ok(tokendata) => {
                /*
                some how assert the type of T to match and return an Err if not matched
                What
                */
                Ok(tokendata.claims)
            },
            Err(err) => {
                // todo: in the future check error kind and give better errors
                Err(InvalidToken{
                    cause: err.to_string()
                })
            }
        }
    }

    pub fn mint_token<T: Serialize>(&self, claims:&T) -> String {
        jwt::encode(&Header::default(), claims, self.secret.as_ref()).unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::util;
    use std::borrow::Borrow;

    #[test]
    fn test_valid() {
        let usr = UserClaims {
            typ: TokenType::User,
            sub:"foobar@gmail.com".to_string(),
            exp:util::current_time_secs()+1,
            usr_id:"usr-1234".to_string(),
        };

        let tf = TokenFactory::new("my_sceret".to_string());

        let token = tf.mint_token(usr.borrow());

        let usr_claims: UserClaims = tf.validate(token).unwrap();

        assert_eq!(usr.sub, usr_claims.sub);
    }

    #[test]
    fn test_mixed() {
        let reg = RegisterClaims {
            typ:TokenType::Reg,
            org_name:"foo".to_string(),
            name:"bar".to_string(),
            email:"foobar@inc".to_string(),
            exp:util::current_time_secs()+1,
        };

        let tf = TokenFactory::new("my_sceret".to_string());

        let token = tf.mint_token(reg.borrow());

        let usr_claims: UserClaims = tf.validate(token).unwrap(); // want it to fail here

        assert_eq!(reg, usr_claims); // fails here
    }
}

1 Ответ

0 голосов
/ 11 октября 2019

Решение, которое я в итоге использовал, состояло в том, чтобы реализовать следующую последовательность для каждой имеющейся у меня структуры заявки.

trait ClaimType {
    fn is_type() -> TokenType;
    fn has_type(&self) -> TokenType;
}

Затем в своем подтверждении я сделал

if T::is_type() == tokendata.claims.has_type() {
    return Ok(tokendata.claims);
}

Err(InvalidToken{
    cause: "Wrong token type".to_string()
})

Я уверен, чтовозможно, это способ использования макроса для обозначения этой черты или заставить саму библиотеку проводить проверку десериализации. Но вышесказанное делает это

...