刚开始学习rust的时候,web框架一大堆,感觉无所适从。有的框架类似于 springboot里注解的方式 使用宏,有的是用函数的方式。
随着异步框架 tokio地位的稳固,axum是一个不错的选择。axum采用的是函数的方式。
其实框架里是写好的验证处理程序的。源码里有基本验证和令牌验证两种方式。
原来有的令牌验证,一是字段不能重新定义,二是字段的值分为两部分。如果前端的人不是深究过http协议,估计会骂街。
前端提交了用户名和密码后,得到了 jwt。后续业务中,将jwt放置到 商量好 的自定义header里即可。
以令牌里只涉及 用户ID 和 过期时间 为例 定义 Claims。
#[derive(Debug, Serialize, Deserialize)] pub struct Claims { uid: String, exp: u64, // Unix stamp at expired time } impl std::fmt::Display for Claims { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self) } }
提取 jwt 获得 claims, 自定义的header为 "x-token"
// 处理从 header获取自定义字段的 jwt,并验证。 #[async_trait] impl<B> axum::extract::FromRequest<B> for Claims where B: Send { type Rejection = AuthError; async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> { let token = req.headers() .get("x-token") .map(|x| x.to_str().unwrap_or("")) .unwrap_or(""); tracing::info!(token); if token.is_empty() { return Err(AuthError::TokenNone); } let token_data = jsonwebtoken::decode::<Claims>(token, &DecodingKey::from_secret(&crate::config::ARGS.get().unwrap().secret.as_bytes()), &Validation::default()) .map_err(|_| AuthError::TokenInvalid)?; // Ok(token_data.claims) } }
处理程序。payload是具体业务数据。需要验证提交的jwt时,参数里加入 claims,就这么简单。
// handler pub async fn auth_jwt(axum::Json(payload): axum::Json<AuthUser>, claims: Claims) -> Result<String, AuthError> { tracing::info!("claim is {:?}", claims); Ok(format!("jwt ok, uid is {},user data {} {}", claims.uid, payload.username, payload.password)) }