Skip to content

Commit 5ff8bb6

Browse files
committed
feat: allow auth middleware to accept access_token query string
1 parent 7658ab2 commit 5ff8bb6

4 files changed

Lines changed: 68 additions & 33 deletions

File tree

‎chat-core/src/middlewares/auth.rs‎

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use axum::{
2-
extract::{FromRequestParts, Request, State},
2+
extract::{FromRequestParts, Query, Request, State},
33
http::StatusCode,
44
middleware::Next,
55
response::{IntoResponse, Response},
@@ -8,39 +8,51 @@ use axum_extra::{
88
TypedHeader,
99
headers::{Authorization, authorization::Bearer},
1010
};
11+
use serde::{Deserialize, Serialize};
1112
use tracing::warn;
1213

1314
use crate::middlewares::TokenVerify;
14-
15+
#[derive(Debug, Deserialize, Serialize)]
16+
struct Params {
17+
access_token: String,
18+
}
1519
pub async fn verify_token<T>(State(state): State<T>, request: Request, next: Next) -> Response
1620
where
1721
T: TokenVerify + Clone + Send + Sync + 'static,
1822
{
1923
let (mut parts, body) = request.into_parts();
20-
let req =
24+
let token =
2125
match TypedHeader::<Authorization<Bearer>>::from_request_parts(&mut parts, &state).await {
22-
Ok(TypedHeader(Authorization(bearer))) => {
23-
let token = bearer.token();
24-
match state.verify(token) {
25-
Ok(claims) => {
26-
let mut req = Request::from_parts(parts, body);
27-
req.extensions_mut().insert(claims);
28-
req
29-
}
30-
Err(err) => {
31-
let msg = format!("verify token failed:{:?}", err);
32-
warn!(msg);
33-
return (StatusCode::FORBIDDEN, msg).into_response();
26+
Ok(TypedHeader(Authorization(bearer))) => bearer.token().to_string(),
27+
Err(err) => {
28+
if err.is_missing() {
29+
match Query::<Params>::from_request_parts(&mut parts, &state).await {
30+
Ok(params) => params.access_token.to_string(),
31+
Err(err) => {
32+
let msg = format!("parse query failed:{}", err);
33+
warn!(msg);
34+
return (StatusCode::UNAUTHORIZED, msg).into_response();
35+
}
3436
}
37+
} else {
38+
let msg = format!("parse Authorization header failed: {}", err);
39+
warn!(msg);
40+
return (StatusCode::UNAUTHORIZED, msg).into_response();
3541
}
3642
}
37-
Err(err) => {
38-
let msg = format!("parse Authorization header failed:{}", err);
39-
warn!(msg);
40-
return (StatusCode::UNAUTHORIZED, msg).into_response();
41-
}
4243
};
43-
44+
let req = match state.verify(&token) {
45+
Ok(claims) => {
46+
let mut req = Request::from_parts(parts, body);
47+
req.extensions_mut().insert(claims);
48+
req
49+
}
50+
Err(err) => {
51+
let msg = format!("verify token failed:{:?}", err);
52+
warn!(msg);
53+
return (StatusCode::FORBIDDEN, msg).into_response();
54+
}
55+
};
4456
next.run(req).await
4557
}
4658

@@ -100,6 +112,11 @@ mod tests {
100112
.layer(from_fn_with_state(state.clone(), verify_token::<AppState>))
101113
.with_state(state);
102114

115+
// no token
116+
let req = Request::builder().uri("/").body(Body::empty())?;
117+
let res = app.clone().oneshot(req).await?;
118+
assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
119+
103120
// good token
104121
let req = Request::builder()
105122
.uri("/")
@@ -108,17 +125,26 @@ mod tests {
108125
let res = app.clone().oneshot(req).await?;
109126
assert_eq!(res.status(), StatusCode::OK);
110127

111-
// no token
112-
let req = Request::builder().uri("/").body(Body::empty())?;
113-
let res = app.clone().oneshot(req).await?;
114-
assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
115-
116128
// bad token
117129
let req = Request::builder()
118130
.uri("/")
119131
.header("Authorization", "Bearer bad-token")
120132
.body(Body::empty())?;
121-
let res = app.oneshot(req).await?;
133+
let res = app.clone().oneshot(req).await?;
134+
assert_eq!(res.status(), StatusCode::FORBIDDEN);
135+
136+
// good token in query
137+
let req = Request::builder()
138+
.uri(format!("/?access_token={token}"))
139+
.body(Body::empty())?;
140+
let res = app.clone().oneshot(req).await?;
141+
assert_eq!(res.status(), StatusCode::OK);
142+
143+
// bad token
144+
let req = Request::builder()
145+
.uri("/?access_token=bad-token".to_string())
146+
.body(Body::empty())?;
147+
let res = app.clone().oneshot(req).await?;
122148
assert_eq!(res.status(), StatusCode::FORBIDDEN);
123149

124150
Ok(())

‎notify-server/index.html‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
<h1>Server Sent Events</h1>
2424

2525
<script lang="javascript">
26-
var source = new EventSource("/events");
26+
let token =
27+
"eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3Nzc3MTUwNTksImV4cCI6MTc3ODMxOTg1OSwibmJmIjoxNzc3NzE1MDU5LCJpc3MiOiJjaGF0X3NlcnZlciIsImF1ZCI6ImNoYXRfd2ViIiwiaWQiOjEsIndzX2lkIjoxLCJmdWxsbmFtZSI6IlR5ciBDaGVuIiwiZW1haWwiOiJ0Y2hlbkBhY21lLm9yZyIsImNyZWF0ZWRfYXQiOiIyMDI2LTA1LTAyVDA3OjI0OjQ5Ljc1Mjc3MVoifQ.TEMT5zhy-O0nx8fpll3FRCJXvkJi6QUXWU-N0Gh73El-Ka7kkf7oao-Zwd8URPB4Piv8g03QIRjAfGMH6tdYDA";
28+
var source = new EventSource(`/events?access_token=${token}`);
2729
source.onmessage = function (event) {
2830
console.log("Got:", event.data);
2931
};

‎notify-server/src/lib.rs‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@ mod sse;
55
use std::{ops::Deref, sync::Arc};
66

77
use anyhow::Result;
8-
use axum::response::{Html, IntoResponse};
9-
use chat_core::{User, middlewares::TokenVerify, utils::DecodingKey};
8+
use axum::{
9+
middleware::from_fn_with_state,
10+
response::{Html, IntoResponse},
11+
};
12+
use chat_core::{
13+
User,
14+
middlewares::{TokenVerify, verify_token},
15+
utils::DecodingKey,
16+
};
1017
use dashmap::DashMap;
1118
pub use notify::setup_pg_listener;
1219
use tokio::sync::broadcast;
@@ -33,7 +40,7 @@ pub fn get_router() -> (axum::Router, AppState) {
3340
let state = AppState::new(config);
3441
let app = axum::Router::new()
3542
.route("/events", axum::routing::get(sse::sse_handler))
36-
//.layer(from_fn_with_state(state.clone(), verify_token::<AppState>))
43+
.layer(from_fn_with_state(state.clone(), verify_token::<AppState>))
3744
.route("/index", axum::routing::get(index_handler))
3845
.with_state(state.clone());
3946
(app, state)

‎notify-server/src/notify.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct ChatUpdated {
3434
// pg_notify('chat_message_created', row_to_json(NEW)::text);
3535
#[derive(Debug, Serialize, Deserialize)]
3636
struct ChatMessageCreated {
37-
messages: Message,
37+
message: Message,
3838
members: Vec<i64>,
3939
}
4040
pub async fn setup_pg_listener(state: AppState) -> anyhow::Result<()> {
@@ -94,7 +94,7 @@ impl Notification {
9494
let user_ids = payload.members.iter().copied().collect();
9595
Ok(Self {
9696
user_ids,
97-
event: Arc::new(AppEvent::NewMessage(payload.messages)),
97+
event: Arc::new(AppEvent::NewMessage(payload.message)),
9898
})
9999
}
100100
_ => Err(anyhow::anyhow!("Invalid notification type")),

0 commit comments

Comments
 (0)