Skip to content

Commit

Permalink
feature: learned axum middleware and finished auth middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
tyrchen committed Apr 29, 2024
1 parent c441bef commit 31d56b5
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 6 deletions.
146 changes: 146 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions chat_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition = "2021"
anyhow = { workspace = true }
argon2 = { version = "0.5.3", features = ["std"] }
axum = { workspace = true }
axum-extra = { version = "0.9.3", features = ["typed-header"] }
chrono = { version = "0.4.38", features = ["serde"] }
jwt-simple = "0.12.9"
serde = { workspace = true }
Expand All @@ -17,8 +18,11 @@ serde_yaml = { workspace = true }
sqlx = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }
tower = "0.4.13"
tower-http = { version = "0.5.2", features = ["compression-full", "trace"] }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
uuid = { version = "1.8.0", features = ["v7", "serde"] }

[dev-dependencies]
http-body-util = "0.1.1"
Expand Down
8 changes: 6 additions & 2 deletions chat_server/src/handlers/chat.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use axum::response::IntoResponse;
use axum::{response::IntoResponse, Extension};
use tracing::info;

pub(crate) async fn list_chat_handler() -> impl IntoResponse {
use crate::User;

pub(crate) async fn list_chat_handler(Extension(user): Extension<User>) -> impl IntoResponse {
info!("user: {:?}", user);
"chat"
}

Expand Down
13 changes: 9 additions & 4 deletions chat_server/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
mod config;
mod error;
mod handlers;
mod middlewares;
mod models;
mod utils;

use anyhow::Context;
use handlers::*;
use middlewares::{set_layer, verify_token};
use sqlx::PgPool;
use std::{fmt, ops::Deref, sync::Arc};
use utils::{DecodingKey, EncodingKey};
Expand All @@ -14,6 +16,7 @@ pub use error::{AppError, ErrorOutput};
pub use models::User;

use axum::{
middleware::from_fn_with_state,
routing::{get, patch, post},
Router,
};
Expand All @@ -37,23 +40,25 @@ pub async fn get_router(config: AppConfig) -> Result<Router, AppError> {
let state = AppState::try_new(config).await?;

let api = Router::new()
.route("/signin", post(signin_handler))
.route("/signup", post(signup_handler))
.route("/chat", get(list_chat_handler).post(create_chat_handler))
.route(
"/chat/:id",
patch(update_chat_handler)
.delete(delete_chat_handler)
.post(send_message_handler),
)
.route("/chat/:id/messages", get(list_message_handler));
.route("/chat/:id/messages", get(list_message_handler))
.layer(from_fn_with_state(state.clone(), verify_token))
// routes doesn't need token verification
.route("/signin", post(signin_handler))
.route("/signup", post(signup_handler));

let app = Router::new()
.route("/", get(index_handler))
.nest("/api", api)
.with_state(state);

Ok(app)
Ok(set_layer(app))
}

// 当我调用 state.config => state.inner.config
Expand Down
42 changes: 42 additions & 0 deletions chat_server/src/middlewares/auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use axum::{
extract::{FromRequestParts, Request, State},
http::StatusCode,
middleware::Next,
response::{IntoResponse, Response},
};
use axum_extra::{
headers::{authorization::Bearer, Authorization},
TypedHeader,
};
use tracing::warn;

use crate::AppState;

pub async fn verify_token(State(state): State<AppState>, req: Request, next: Next) -> Response {
let (mut parts, body) = req.into_parts();
let req =
match TypedHeader::<Authorization<Bearer>>::from_request_parts(&mut parts, &state).await {
Ok(TypedHeader(Authorization(bearer))) => {
let token = bearer.token();
match state.dk.verify(token) {
Ok(user) => {
let mut req = Request::from_parts(parts, body);
req.extensions_mut().insert(user);
req
}
Err(e) => {
let msg = format!("verify token failed: {}", e);
warn!(msg);
return (StatusCode::FORBIDDEN, msg).into_response();
}
}
}
Err(e) => {
let msg = format!("parse Authorization header failed: {}", e);
warn!(msg);
return (StatusCode::UNAUTHORIZED, msg).into_response();
}
};

next.run(req).await
}
Loading

0 comments on commit 31d56b5

Please sign in to comment.