Skip to content

Commit

Permalink
更新ApiResult&Middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
shenghui0779 committed Oct 29, 2024
1 parent e5cd50a commit b926d12
Show file tree
Hide file tree
Showing 25 changed files with 339 additions and 382 deletions.
268 changes: 140 additions & 128 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ description = "API project template for Rust"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
futures = "0.3"
tokio = { version = "1", features = ["full"] }
clap = { version = "4.5", features = ["derive"] }
hostname = "^0.4"
Expand Down Expand Up @@ -39,7 +40,7 @@ hyper = "1.0"
http = "1.0"
http-body = "1.0"
http-body-util = "0.1"
tower-http = { version = "0.6", features = ["trace"] }
tower-http = { version = "0.6", features = ["cors"] }
axum = { version = "0.7", features = ["macros"] }
axum-extra = "0.9"
nanoid = "0.4"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
- 参数验证器使用 [validator](https://github.com/Keats/validator)
- 包含基础的登录授权功能
- 包含基于 Redis 的分布式锁
- 包含 认证、请求日志、跨域 中间价
- 包含 AES、Hash、时间格式化 等实用封装
- 包含 Trace、认证、请求日志、Panic捕获 中间价
- 简单好用的 API Result 统一输出方式

#### 1. 模块说明
Expand All @@ -30,5 +30,5 @@ demo_rs.sql
mv config.toml.example config.toml

# 启动服务
cargo run -- serve
cargo run serve
```
20 changes: 8 additions & 12 deletions src/app/api/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ use axum_extra::extract::WithRejection;
use validator::Validate;

use crate::shared::{
result::{
rejection::IRejection,
response::{ApiErr, ApiOK},
Result,
},
result::{code::Code, rejection::IRejection, ApiResult},
util::identity::{Identity, Role},
};

Expand All @@ -24,32 +20,32 @@ use crate::app::service::{
pub async fn create(
Extension(identity): Extension<Identity>,
WithRejection(Json(req), _): IRejection<Json<ReqCreate>>,
) -> Result<ApiOK<()>> {
) -> ApiResult<()> {
if !identity.is_role(Role::Super) {
return Err(ApiErr::ErrPerm(None));
return Err(Code::ErrPerm(None));
}
if let Err(e) = req.validate() {
return Err(ApiErr::ErrParams(Some(e.to_string())));
return Err(Code::ErrParams(Some(e.to_string())));
}
service::account::create(req).await
}

pub async fn info(
Extension(identity): Extension<Identity>,
Path(account_id): Path<u64>,
) -> Result<ApiOK<RespInfo>> {
) -> ApiResult<RespInfo> {
if !identity.is_role(Role::Super) {
return Err(ApiErr::ErrPerm(None));
return Err(Code::ErrPerm(None));
}
service::account::info(account_id).await
}

pub async fn list(
Extension(identity): Extension<Identity>,
Query(query): Query<HashMap<String, String>>,
) -> Result<ApiOK<RespList>> {
) -> ApiResult<RespList> {
if !identity.is_role(Role::Super) {
return Err(ApiErr::ErrPerm(None));
return Err(Code::ErrPerm(None));
}
service::account::list(query).await
}
14 changes: 5 additions & 9 deletions src/app/api/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ use axum_extra::extract::WithRejection;
use validator::Validate;

use crate::shared::{
result::{
rejection::IRejection,
response::{ApiErr, ApiOK},
Result,
},
result::{code::Code, rejection::IRejection, reply, ApiResult},
util::identity::Identity,
};

Expand All @@ -18,16 +14,16 @@ use crate::app::service::{

pub async fn login(
WithRejection(Json(req), _): IRejection<Json<ReqLogin>>,
) -> Result<ApiOK<RespLogin>> {
) -> ApiResult<RespLogin> {
if let Err(e) = req.validate() {
return Err(ApiErr::ErrParams(Some(e.to_string())));
return Err(Code::ErrParams(Some(e.to_string())));
}
service::auth::login(req).await
}

pub async fn logout(Extension(identity): Extension<Identity>) -> Result<ApiOK<()>> {
pub async fn logout(Extension(identity): Extension<Identity>) -> ApiResult<()> {
if identity.id() == 0 {
return Ok(ApiOK(None));
return Ok(reply::OK(None));
}
service::auth::logout(identity).await
}
14 changes: 5 additions & 9 deletions src/app/api/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ use axum_extra::extract::WithRejection;
use validator::Validate;

use crate::shared::{
result::{
rejection::IRejection,
response::{ApiErr, ApiOK},
Result,
},
result::{code::Code, rejection::IRejection, ApiResult},
util::identity::Identity,
};

Expand All @@ -24,23 +20,23 @@ use crate::app::service::{
pub async fn create(
Extension(identity): Extension<Identity>,
WithRejection(Json(req), _): IRejection<Json<ReqCreate>>,
) -> Result<ApiOK<()>> {
) -> ApiResult<()> {
if let Err(e) = req.validate() {
return Err(ApiErr::ErrParams(Some(e.to_string())));
return Err(Code::ErrParams(Some(e.to_string())));
}
service::project::create(identity, req).await
}

pub async fn list(
Extension(identity): Extension<Identity>,
Query(query): Query<HashMap<String, String>>,
) -> Result<ApiOK<RespList>> {
) -> ApiResult<RespList> {
service::project::list(identity, query).await
}

pub async fn detail(
Extension(identity): Extension<Identity>,
Path(project_id): Path<u64>,
) -> Result<ApiOK<RespDetail>> {
) -> ApiResult<RespDetail> {
service::project::detail(identity, project_id).await
}
2 changes: 1 addition & 1 deletion src/app/cmd/hello.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pub fn exec(name: String) {
println!("hello {}!", name)
println!("hello {}!", name);
}
6 changes: 3 additions & 3 deletions src/app/middleware/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ use axum::{
response::{IntoResponse, Response},
};

use crate::shared::{result::response::ApiErr, util::identity::Identity};
use crate::shared::{result::code::Code, util::identity::Identity};

use super::auth_check;

pub async fn handle(request: Request, next: Next) -> Response {
let identity = request.extensions().get::<Identity>();
match identity {
None => return ApiErr::ErrAuth(None).into_response(),
None => return Code::ErrAuth(None).into_response(),
Some(v) => match auth_check(v).await {
Ok(_) => (),
Err(e) => return ApiErr::ErrAuth(Some(e.to_string())).into_response(),
Err(e) => return Code::ErrAuth(Some(e.to_string())).into_response(),
},
}
next.run(request).await
Expand Down
7 changes: 4 additions & 3 deletions src/app/router/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use axum::{
routing::{get, post},
Router,
};
use tower_http::cors::CorsLayer;

use crate::{
app::{
Expand Down Expand Up @@ -29,7 +30,7 @@ pub fn init() -> Router {
.route("/", get(|| async { "☺ welcome to Rust app" }))
.nest("/v1", open.merge(auth))
.layer(axum::middleware::from_fn(middleware::log::handle))
.layer(axum::middleware::from_fn(middleware::identity::handle))
.layer(axum::middleware::from_fn(middleware::cors::handle))
.layer(axum::middleware::from_fn(middleware::trace_id::handle))
.layer(CorsLayer::very_permissive().expose_headers(vec![middleware::trace::TRACE_ID]))
.layer(axum::middleware::from_fn(middleware::catch_panic::handle))
.layer(axum::middleware::from_fn(middleware::trace::handle))
}
30 changes: 15 additions & 15 deletions src/app/service/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use validator::Validate;

use crate::shared::core::db;
use crate::shared::crypto::hash;
use crate::shared::result;
use crate::shared::result::response::{ApiErr, ApiOK};
use crate::shared::result::code::Code;
use crate::shared::result::{reply, ApiResult};
use crate::shared::util::{helper, xtime};

use crate::app::model::{account, prelude::Account};
Expand All @@ -24,17 +24,17 @@ pub struct ReqCreate {
pub realname: String,
}

pub async fn create(req: ReqCreate) -> result::Result<ApiOK<()>> {
pub async fn create(req: ReqCreate) -> ApiResult<()> {
let count = Account::find()
.filter(account::Column::Username.eq(req.username.clone()))
.count(db::conn())
.await
.map_err(|e| {
tracing::error!(error = ?e, "error find account");
ApiErr::ErrSystem(None)
Code::ErrSystem(None)
})?;
if count > 0 {
return Err(ApiErr::ErrPerm(Some("该用户名已被使用".to_string())));
return Err(Code::ErrPerm(Some("该用户名已被使用".to_string())));
}

let salt = helper::nonce(16);
Expand All @@ -53,10 +53,10 @@ pub async fn create(req: ReqCreate) -> result::Result<ApiOK<()>> {

if let Err(e) = Account::insert(model).exec(db::conn()).await {
tracing::error!(error = ?e, "error insert account");
return Err(ApiErr::ErrSystem(None));
return Err(Code::ErrSystem(None));
}

Ok(ApiOK(None))
Ok(reply::OK(None))
}

#[derive(Debug, Serialize)]
Expand All @@ -70,15 +70,15 @@ pub struct RespInfo {
pub created_at_str: String,
}

pub async fn info(account_id: u64) -> result::Result<ApiOK<RespInfo>> {
pub async fn info(account_id: u64) -> ApiResult<RespInfo> {
let model = Account::find_by_id(account_id)
.one(db::conn())
.await
.map_err(|e| {
tracing::error!(error = ?e, "error find account");
ApiErr::ErrSystem(None)
Code::ErrSystem(None)
})?
.ok_or(ApiErr::ErrNotFound(Some("账号不存在".to_string())))?;
.ok_or(Code::ErrEmpty(Some("账号不存在".to_string())))?;

let resp = RespInfo {
id: model.id,
Expand All @@ -91,7 +91,7 @@ pub async fn info(account_id: u64) -> result::Result<ApiOK<RespInfo>> {
.unwrap_or_default(),
};

Ok(ApiOK(Some(resp)))
Ok(reply::OK(Some(resp)))
}

#[derive(Debug, Serialize)]
Expand All @@ -100,7 +100,7 @@ pub struct RespList {
pub list: Vec<RespInfo>,
}

pub async fn list(query: HashMap<String, String>) -> result::Result<ApiOK<RespList>> {
pub async fn list(query: HashMap<String, String>) -> ApiResult<RespList> {
let mut builder = Account::find();
if let Some(username) = query.get("username") {
if !username.is_empty() {
Expand All @@ -121,7 +121,7 @@ pub async fn list(query: HashMap<String, String>) -> result::Result<ApiOK<RespLi
.await
.map_err(|e| {
tracing::error!(error = ?e, "error count account");
ApiErr::ErrSystem(None)
Code::ErrSystem(None)
})?
.unwrap_or_default();
}
Expand All @@ -134,7 +134,7 @@ pub async fn list(query: HashMap<String, String>) -> result::Result<ApiOK<RespLi
.await
.map_err(|e| {
tracing::error!(error = ?e, "error find account");
ApiErr::ErrSystem(None)
Code::ErrSystem(None)
})?;
let mut resp = RespList {
total,
Expand All @@ -155,5 +155,5 @@ pub async fn list(query: HashMap<String, String>) -> result::Result<ApiOK<RespLi
resp.list.push(info);
}

Ok(ApiOK(Some(resp)))
Ok(reply::OK(Some(resp)))
}
24 changes: 12 additions & 12 deletions src/app/service/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use validator::Validate;
use crate::app::model::{account, prelude::Account};
use crate::shared::core::db;
use crate::shared::crypto::hash;
use crate::shared::result;
use crate::shared::result::response::{ApiErr, ApiOK};
use crate::shared::result::code::Code;
use crate::shared::result::{reply, ApiResult};
use crate::shared::util::identity::Identity;
use crate::shared::util::{helper, xtime};

Expand All @@ -26,20 +26,20 @@ pub struct RespLogin {
pub auth_token: String,
}

pub async fn login(req: ReqLogin) -> result::Result<ApiOK<RespLogin>> {
pub async fn login(req: ReqLogin) -> ApiResult<RespLogin> {
let model = Account::find()
.filter(account::Column::Username.eq(req.username))
.one(db::conn())
.await
.map_err(|e| {
tracing::error!(error = ?e, "error find account");
ApiErr::ErrSystem(None)
Code::ErrSystem(None)
})?
.ok_or(ApiErr::ErrAuth(Some("账号不存在".to_string())))?;
.ok_or(Code::ErrAuth(Some("账号不存在".to_string())))?;

let pass = format!("{}{}", req.password, model.salt);
if hash::md5(pass.as_bytes()) != model.password {
return Err(ApiErr::ErrAuth(Some("密码错误".to_string())));
return Err(Code::ErrAuth(Some("密码错误".to_string())));
}

let now = xtime::now(None).unix_timestamp();
Expand All @@ -49,7 +49,7 @@ pub async fn login(req: ReqLogin) -> result::Result<ApiOK<RespLogin>> {
.to_auth_token()
.map_err(|e| {
tracing::error!(error = ?e, "error identity encrypt");
ApiErr::ErrSystem(None)
Code::ErrSystem(None)
})?;
let update_model = account::ActiveModel {
login_at: Set(now),
Expand All @@ -64,7 +64,7 @@ pub async fn login(req: ReqLogin) -> result::Result<ApiOK<RespLogin>> {
.await;
if let Err(e) = ret_update {
tracing::error!(error = ?e, "error update account");
return Err(ApiErr::ErrSystem(None));
return Err(Code::ErrSystem(None));
}

let resp = RespLogin {
Expand All @@ -73,10 +73,10 @@ pub async fn login(req: ReqLogin) -> result::Result<ApiOK<RespLogin>> {
auth_token,
};

Ok(ApiOK(Some(resp)))
Ok(reply::OK(Some(resp)))
}

pub async fn logout(identity: Identity) -> result::Result<ApiOK<()>> {
pub async fn logout(identity: Identity) -> ApiResult<()> {
let ret = Account::update_many()
.filter(account::Column::Id.eq(identity.id()))
.col_expr(account::Column::LoginToken, Expr::value(""))
Expand All @@ -89,8 +89,8 @@ pub async fn logout(identity: Identity) -> result::Result<ApiOK<()>> {

if let Err(e) = ret {
tracing::error!(error = ?e, "error update account");
return Err(ApiErr::ErrSystem(None));
return Err(Code::ErrSystem(None));
}

Ok(ApiOK(None))
Ok(reply::OK(None))
}
Loading

0 comments on commit b926d12

Please sign in to comment.