fusion_web/
util.rs

1use axum::Json;
2use axum::extract::Query;
3use axum::http::StatusCode;
4use axum::http::request::Parts;
5use headers::authorization::Bearer;
6use headers::{Authorization, HeaderMapExt};
7use serde::de::DeserializeOwned;
8#[cfg(feature = "with-ulid")]
9use ulid::Ulid;
10
11use fusion_common::ctx::Ctx;
12use fusion_common::model::IdI64Result;
13use fusion_common::time::now_offset;
14use fusion_core::configuration::SecuritySetting;
15use fusion_core::log::get_trace_id;
16use fusion_core::security::{AccessToken, SecurityUtils};
17
18use crate::WebResult;
19use crate::error::WebError;
20
21/// ok_json! 宏:支持无参数(返回 Ok(Json(())))或一个参数(返回 Ok(Json(v)))
22#[macro_export]
23macro_rules! ok_json {
24  () => {
25    Ok(axum::Json(().into()))
26  };
27  ($v:expr) => {
28    Ok(axum::Json($v))
29  };
30}
31
32#[inline]
33pub fn ok_id(id: i64) -> WebResult<IdI64Result> {
34  Ok(IdI64Result::new(id).into())
35}
36
37#[cfg(feature = "with-ulid")]
38#[inline]
39pub fn ok_ulid(id: Ulid) -> WebResult<fusion_common::model::IdUlidResult> {
40  Ok(fusion_common::model::IdUlidResult::new(id).into())
41}
42
43#[cfg(feature = "with-uuid")]
44#[inline]
45pub fn ok_uuid(id: uuid::Uuid) -> WebResult<fusion_common::model::IdUuidResult> {
46  Ok(fusion_common::model::IdUuidResult::new(id).into())
47}
48
49pub fn unauthorized_app_error(msg: impl Into<String>) -> (StatusCode, Json<WebError>) {
50  (StatusCode::UNAUTHORIZED, Json(WebError::new_with_msg(msg).with_err_code(401)))
51}
52
53/// 从 Http Request Authorization Header 或 access_token query 中获取 [Ctx]
54pub fn extract_ctx(parts: &Parts, sc: &SecuritySetting) -> Result<Ctx, WebError> {
55  let req_time = now_offset();
56
57  let token = if let Some(Authorization(bearer)) = parts.headers.typed_get::<Authorization<Bearer>>() {
58    bearer.token().to_string()
59  } else if let Ok(at) = Query::<AccessToken>::try_from_uri(&parts.uri) {
60    at.0.access_token
61  } else {
62    return Err(WebError::new_with_code(401, "Missing token"));
63  };
64
65  let (payload, _) =
66    SecurityUtils::decrypt_jwt(sc.pwd(), &token).map_err(|_e| WebError::new_with_code(401, "Failed decode jwt"))?;
67
68  let ctx =
69    Ctx::try_new(payload, Some(req_time), get_trace_id()).map_err(|e| WebError::new_with_code(401, e.to_string()))?;
70  Ok(ctx)
71}
72
73pub fn opt_to_app_result<T>(opt: Option<T>) -> WebResult<T>
74where
75  T: DeserializeOwned,
76{
77  if let Some(v) = opt { Ok(Json(v)) } else { Err(WebError::new_with_code(404, "Not found.")) }
78}