rust - 我应该如何在 rust 中强制执行 jsonwebtokens 的反序列化类型?
问题描述
以下是我使用 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
}
}
解决方案
我最终使用的解决方案是为我拥有的每个声明结构实施以下训练。
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()
})
我确定可能有一种方法可以使用宏来为我实现特征,或者让库本身强制执行一些反序列化检查。但是上面完成了
推荐阅读
- logstash - 用流利的日志时间更新时间戳/时间键没有运气
- c# - 使用网络应用程序通过机器人主动发送消息
- sql - How to exclude a certain range in SQL results?
- rest - 微服务/REST - 如何在其他服务中存储对资源的引用
- python - 在扭曲脚本的 SIGTERM 上终止 docker 容器
- swift - 如何避免这种强制施法
- javascript - 如何使用 App Access Token 更新 Open Graph 标签
- java - 如何将数组索引转换为车和象棋棋子的可能移动
- java - 设置背景自定义颜色,XSSFWorkbook
- python - GIMP Python - 用颜色填充路径/矢量