mikkyang / rust-jwt

JSON Web Token library for Rust
MIT License
178 stars 38 forks source link

implementation of `serde::de::Deserialize` is not general enough #91

Open Necoo33 opened 1 year ago

Necoo33 commented 1 year ago

Hello, i want to make an authentication flow with your package but i take that error.

My related codes like this:

in models crate:


#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
pub struct UserForAuth {
    pub id: String,
    pub nickname: String,
    pub email: String,
    pub role: String,
}

in authlogic crate:


use hmac::{Hmac, Mac};
use jwt::{SignWithKey, VerifyWithKey};
use sha2::Sha256;
use std::collections::BTreeMap;

extern crate models;

pub fn create_jwt(user_struct: models::UserForAuth, secret_key: &[u8]) -> String {
    let jwt_key: Hmac<Sha256> = Hmac::new_from_slice(secret_key).unwrap();
    let mut new_claim = BTreeMap::new();

    new_claim.insert("user", user_struct);

    return new_claim.sign_with_key(&jwt_key).unwrap();
}

pub fn verify_jwt_and_return_values(jwt_value: &str, secret_key: &str) -> Option<models::UserForAuth> {
    let format_the_u8 = format!("b{}", secret_key);

    let new_key: Hmac<Sha256> = Hmac::new_from_slice(&format_the_u8.as_bytes()).unwrap();

    let existing_claim: BTreeMap<&str, models::UserForAuth> = jwt_value.verify_with_key(&new_key).unwrap();

    return Some(existing_claim["user"].clone());
}

and i take that error:

error: implementation of serde::de::Deserialize is not general enough --> authlogic\src\lib.rs:22:63 22 let existing_claim: BTreeMap<&str, models::UserForAuth> = jwt_value.verify_with_key(&new_key).unwrap(); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of serde::de::Deserialize is not general enough

= note: BTreeMap<&str, UserForAuth> must implement serde::de::Deserialize<'0>, for any lifetime '0... = note: ...but it actually implements serde::de::Deserialize<'1>, for some specific lifetime '1

error: could not compile authlogic (lib) due to previous error

So how do i fix that error?

gpollatos commented 1 year ago

Hey, I am very very new to Rust and I am also using this library and saw your issue. The solution in this case is to declare your existing_claim as:

let existing_claim: BTreeMap<String, models::UserForAuth> = jwt_value.verify_with_key(&new_key).unwrap();

Unfortunately I cannot in detail articulate yet why exactly &str is problematic but I started reading this post and trying to understand the why.

Furthermore in your code this part is also problematic:

let format_the_u8 = format!("b{}", secret_key);
let new_key: Hmac<Sha256> = Hmac::new_from_slice(&format_the_u8.as_bytes()).unwrap();

and results in a MACError since as afar as I understand so far b{} doesn't do the conversion you wish.

Here's a working modification of your code:

fn main() {
    let user = UserForAuth{
        id: String::from("some_id"),
        nickname: String::from("some_nickname"),
        email: String::from("some_email"),
        role: String::from("some_role"),
    };
    let tok = create_jwt(user, b"some-secret");
    let u =  verify_jwt_and_return_values(tok.as_str(), "some-secret").unwrap();
    println!("{:?}", u);
}

#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
pub struct UserForAuth {
    pub id: String,
    pub nickname: String,
    pub email: String,
    pub role: String,
}

pub fn create_jwt(user_struct: UserForAuth, secret_key: &[u8]) -> String {
    let jwt_key: Hmac<Sha256> = Hmac::new_from_slice(secret_key).unwrap();
    let mut new_claim = BTreeMap::new();
    new_claim.insert("user", user_struct);
    return new_claim.sign_with_key(&jwt_key).unwrap();
}

pub fn verify_jwt_and_return_values(jwt_value: &str, secret_key: &str) -> Option<UserForAuth> {
    let new_key: Hmac<Sha256> = Hmac::new_from_slice(secret_key.as_bytes()).unwrap();
    println!("{:?}", new_key);
    let result: Result<BTreeMap<String, UserForAuth>, Error> = jwt_value.verify_with_key(&new_key);
    match result {
        Ok(existing_claim) => Some(existing_claim["user"].clone()),
        Err(e) => {
            println!("{}", e);
            None
        }
    }
}

Hope it helps!

Necoo33 commented 1 year ago

Hey, I am very very new to Rust and I am also using this library and saw your issue. The solution in this case is to declare your existing_claim as:

let existing_claim: BTreeMap<String, models::UserForAuth> = jwt_value.verify_with_key(&new_key).unwrap();

Unfortunately I cannot in detail articulate yet why exactly &str is problematic but I started reading this post and trying to understand the why.

Furthermore in your code this part is also problematic:

let format_the_u8 = format!("b{}", secret_key);
let new_key: Hmac<Sha256> = Hmac::new_from_slice(&format_the_u8.as_bytes()).unwrap();

and results in a MACError since as afar as I understand so far b{} doesn't do the conversion you wish.

Here's a working modification of your code:

fn main() {
    let user = UserForAuth{
        id: String::from("some_id"),
        nickname: String::from("some_nickname"),
        email: String::from("some_email"),
        role: String::from("some_role"),
    };
    let tok = create_jwt(user, b"some-secret");
    let u =  verify_jwt_and_return_values(tok.as_str(), "some-secret").unwrap();
    println!("{:?}", u);
}

#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
pub struct UserForAuth {
    pub id: String,
    pub nickname: String,
    pub email: String,
    pub role: String,
}

pub fn create_jwt(user_struct: UserForAuth, secret_key: &[u8]) -> String {
    let jwt_key: Hmac<Sha256> = Hmac::new_from_slice(secret_key).unwrap();
    let mut new_claim = BTreeMap::new();
    new_claim.insert("user", user_struct);
    return new_claim.sign_with_key(&jwt_key).unwrap();
}

pub fn verify_jwt_and_return_values(jwt_value: &str, secret_key: &str) -> Option<UserForAuth> {
    let new_key: Hmac<Sha256> = Hmac::new_from_slice(secret_key.as_bytes()).unwrap();
    println!("{:?}", new_key);
    let result: Result<BTreeMap<String, UserForAuth>, Error> = jwt_value.verify_with_key(&new_key);
    match result {
        Ok(existing_claim) => Some(existing_claim["user"].clone()),
        Err(e) => {
            println!("{}", e);
            None
        }
    }
}

Hope it helps!

it's interesting to see. This error is most mysterious and implicit error in rust i ever seen, definitely contrary to rust's error policy. I was changed another package to solve my problem and i could implemented it successfully. I don't think to use this package anymore.