完善request context中间件,错误信息使用i18n处理

This commit is contained in:
李运家 2024-09-27 18:52:32 +08:00
parent 461edb0f25
commit 0d8802b495
5 changed files with 26 additions and 8 deletions

View File

@ -12,3 +12,4 @@ ValidateAccountIdTokenRequired,ID Token is required,用户ID Token不能为空
ValidateAccountLangTagRequired,lang tag is required,用户语言标识不能为空 ValidateAccountLangTagRequired,lang tag is required,用户语言标识不能为空
ValidatePageablePageRequired,invalid page number,页码无效 ValidatePageablePageRequired,invalid page number,页码无效
ValidatePageablePageSizeRequired,invalid quantity per page,每页数量无效 ValidatePageablePageSizeRequired,invalid quantity per page,每页数量无效
BadRequest,bad request,无效请求
1 id en-US zh-CN
12 ValidateAccountLangTagRequired lang tag is required 用户语言标识不能为空
13 ValidatePageablePageRequired invalid page number 页码无效
14 ValidatePageablePageSizeRequired invalid quantity per page 每页数量无效
15 BadRequest bad request 无效请求

View File

@ -2,7 +2,9 @@ use strum_macros::{AsRefStr, Display, EnumIter, EnumString};
#[derive(Debug, EnumIter, EnumString, Display, PartialEq, AsRefStr)] #[derive(Debug, EnumIter, EnumString, Display, PartialEq, AsRefStr)]
pub enum MessageId { pub enum MessageId {
BadRequest,
ServerInternalError, ServerInternalError,
Hello, Hello,
AccountDisabled, AccountDisabled,
AccountNoPermission, AccountNoPermission,

View File

@ -1,5 +1,6 @@
use axum::{extract::Request, middleware::Next, response::{IntoResponse, Response}}; use axum::{extract::Request, middleware::Next, response::{IntoResponse, Response}};
use http::{header, StatusCode}; use http::{header, StatusCode};
use i18n::{message, message_ids::MessageId};
use jsonwebtoken::{decode, DecodingKey, Validation}; use jsonwebtoken::{decode, DecodingKey, Validation};
use crate::{cache::account_cache::LOGIN_CACHE, config, context::{Context, WhiteContext}, token::Claims}; use crate::{cache::account_cache::LOGIN_CACHE, config, context::{Context, WhiteContext}, token::Claims};
@ -11,6 +12,7 @@ const WHITE_LIST: &[(&str, &str)] = &[
/// 认证中间件包括网络请求白名单、token验证、登录缓存 /// 认证中间件包括网络请求白名单、token验证、登录缓存
pub async fn authenticate_ctx(mut req: Request, next: Next) -> Response { pub async fn authenticate_ctx(mut req: Request, next: Next) -> Response {
let mut language = String::from("zh-CN");
// 获取请求的url和method然后判断是否在白名单中如果在白名单中则直接返回next(req),否则继续执行下面的代码 // 获取请求的url和method然后判断是否在白名单中如果在白名单中则直接返回next(req),否则继续执行下面的代码
let method = req.method().clone().to_string(); let method = req.method().clone().to_string();
let uri = req.uri().path_and_query().unwrap().to_string(); let uri = req.uri().path_and_query().unwrap().to_string();
@ -19,16 +21,16 @@ pub async fn authenticate_ctx(mut req: Request, next: Next) -> Response {
}).is_some() { }).is_some() {
// 解析语言 // 解析语言
let language_header = req.headers().get(header::ACCEPT_LANGUAGE); let language_header = req.headers().get(header::ACCEPT_LANGUAGE);
let language = match language_header { language = match language_header {
Some(value) => { Some(value) => {
let value_str: Vec<&str> = value.to_str().unwrap_or("zh-CN").split(',').collect(); let value_str: Vec<&str> = value.to_str().unwrap_or("zh-CN").split(',').collect();
if value_str.is_empty() { if value_str.is_empty() {
String::from("zh-CN") language
} else { } else {
String::from(value_str[0]) String::from(value_str[0])
} }
}, },
None => String::from("zh-CN"), None => language,
}; };
req.extensions_mut().insert(WhiteContext { lang_tag: language }); req.extensions_mut().insert(WhiteContext { lang_tag: language });
return next.run(req).await; return next.run(req).await;
@ -40,11 +42,15 @@ pub async fn authenticate_ctx(mut req: Request, next: Next) -> Response {
Some(header_value) => { Some(header_value) => {
let parts: Vec<&str> = header_value.to_str().unwrap_or("").split_whitespace().collect(); let parts: Vec<&str> = header_value.to_str().unwrap_or("").split_whitespace().collect();
if parts.len() != 2 || parts[0] != "Bearer" { if parts.len() != 2 || parts[0] != "Bearer" {
return (StatusCode::BAD_REQUEST, "Invalid authorization header format".to_string()).into_response(); tracing::error!("无效的 authorization 请求头参数");
return (StatusCode::BAD_REQUEST, message!(&language, MessageId::BadRequest)).into_response();
} }
parts[1] parts[1]
}, },
None => return (StatusCode::UNAUTHORIZED, "Missing authorization header".to_string()).into_response(), None => {
tracing::error!("缺少 authorization 请求头参数");
return (StatusCode::UNAUTHORIZED, message!(&language, MessageId::BadRequest)).into_response()
},
}; };
let validation = Validation::default(); let validation = Validation::default();
@ -53,7 +59,8 @@ pub async fn authenticate_ctx(mut req: Request, next: Next) -> Response {
// 从缓存中获取当前用户信息 // 从缓存中获取当前用户信息
let account = LOGIN_CACHE.get(&decoded.claims.sub).await; let account = LOGIN_CACHE.get(&decoded.claims.sub).await;
if account.is_none() { if account.is_none() {
return (StatusCode::UNAUTHORIZED, "Invalid token".to_string()).into_response(); tracing::error!("无效的 token");
return (StatusCode::UNAUTHORIZED, message!(&language, MessageId::BadRequest)).into_response();
} }
let account = account.unwrap(); let account = account.unwrap();
// 判断token是否有效(注释掉,如果服务因为升级等原因手动重启了,缓存的数据也不再存在) // 判断token是否有效(注释掉,如果服务因为升级等原因手动重启了,缓存的数据也不再存在)
@ -69,6 +76,9 @@ pub async fn authenticate_ctx(mut req: Request, next: Next) -> Response {
}); });
next.run(req).await next.run(req).await
}, },
Err(_) => (StatusCode::UNAUTHORIZED, "Invalid token".to_string()).into_response(), Err(_) => {
tracing::error!("无效的 token");
return (StatusCode::UNAUTHORIZED, message!(&language, MessageId::BadRequest)).into_response();
}
} }
} }

View File

@ -5,6 +5,7 @@ use library::{context::{Context, WhiteContext}, model::{response::ResResult, val
use crate::service; use crate::service;
/// post: /account/google /// post: /account/google
///
/// google账号登录 /// google账号登录
pub async fn authenticate_google( pub async fn authenticate_google(
Extension(context): Extension<WhiteContext>, Extension(context): Extension<WhiteContext>,
@ -15,6 +16,7 @@ pub async fn authenticate_google(
} }
/// post: /account/sys /// post: /account/sys
///
/// 账号密码登录 /// 账号密码登录
pub async fn authenticate_with_password( pub async fn authenticate_with_password(
Extension(context): Extension<WhiteContext>, Extension(context): Extension<WhiteContext>,
@ -25,6 +27,7 @@ pub async fn authenticate_with_password(
} }
/// post: /account/refresh-token /// post: /account/refresh-token
///
/// 刷新token /// 刷新token
pub async fn refresh_token( pub async fn refresh_token(
Extension(context): Extension<Context>, Extension(context): Extension<Context>,

View File

@ -10,6 +10,7 @@ use library::model::validator;
use crate::service; use crate::service;
/// post: /feedback /// post: /feedback
///
/// 添加反馈信息 /// 添加反馈信息
pub async fn add_feedback( pub async fn add_feedback(
Extension(context): Extension<Context>, Extension(context): Extension<Context>,
@ -20,6 +21,7 @@ pub async fn add_feedback(
} }
/// get: /feedback /// get: /feedback
///
/// 获取反馈信息列表 /// 获取反馈信息列表
pub async fn get_feedback_list_by_page( pub async fn get_feedback_list_by_page(
Extension(context): Extension<Context>, Extension(context): Extension<Context>,