Implemented GET and PATCH handler
This commit is contained in:
@ -10,6 +10,11 @@ COPY Cargo.toml Cargo.lock ./
|
||||
# Copy source code
|
||||
COPY src ./src
|
||||
|
||||
# Install runtime dependencies (if needed, e.g., for SSL)
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends ca-certificates libssl-dev pkg-config && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Build for release
|
||||
RUN cargo build --release
|
||||
|
||||
@ -18,7 +23,7 @@ FROM debian:bookworm-slim
|
||||
|
||||
# Install runtime dependencies (if needed, e.g., for SSL)
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends ca-certificates && \
|
||||
apt-get install -y --no-install-recommends ca-certificates libssl-dev && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create non-root user
|
||||
|
||||
@ -23,7 +23,7 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
container_name: rust-microservice
|
||||
ports:
|
||||
- "3000:8080"
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- RUST_LOG=info
|
||||
|
||||
176
src/api.rs
176
src/api.rs
@ -95,6 +95,182 @@ pub async fn handle_post(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_get(
|
||||
Extension(state): Extension<Arc<AppState>>,
|
||||
request: Request<Body>,
|
||||
) -> impl IntoResponse {
|
||||
let cloned_state = state.clone();
|
||||
let (mut parts, body) = request.into_parts();
|
||||
let body_bytes = axum::body::to_bytes(body, usize::MAX).await.unwrap();
|
||||
|
||||
let mut forwarded_request = cloned_state
|
||||
.gsd_service
|
||||
.forward_get_request(Request::from_parts(
|
||||
parts.clone(),
|
||||
Body::from(body_bytes.clone()),
|
||||
))
|
||||
.await;
|
||||
|
||||
if forwarded_request.is_err() {
|
||||
error!(
|
||||
"Failed to forward post: {:?}",
|
||||
forwarded_request.err().unwrap()
|
||||
);
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
}
|
||||
|
||||
|
||||
let content_type = forwarded_request.as_ref().unwrap().headers().get("Content-Type").unwrap().to_str().unwrap();
|
||||
if content_type == "application/json" {
|
||||
let content_text = forwarded_request.unwrap().text().await;
|
||||
if content_text.is_err() {
|
||||
error!("Failed to read content text: {:?}", content_text.err());
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
}
|
||||
|
||||
let content = serde_json::from_str::<GSDResponseDTO>(content_text.as_ref().unwrap().as_str());
|
||||
if content.is_err() {
|
||||
error!("Failed to read content json: {:?}", content.err());
|
||||
error!("Content: {:?}", content_text);
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
}
|
||||
|
||||
let content_unwrapped = content.unwrap();
|
||||
// Invalid session
|
||||
if content_unwrapped.status.is_some()
|
||||
&& content_unwrapped.status.unwrap().internal_status == "201"
|
||||
{
|
||||
info!("Session invalid. Re-negotiate new session");
|
||||
|
||||
match cloned_state.gsd_service.get_session().await {
|
||||
Ok(session) => {
|
||||
set_and_log_session(&cloned_state, session.clone()).await;
|
||||
|
||||
parts.headers.remove("sessionId");
|
||||
parts.headers.insert(
|
||||
"sessionId",
|
||||
HeaderValue::from_str(session.clone().as_str()).unwrap(),
|
||||
);
|
||||
|
||||
forwarded_request = cloned_state
|
||||
.gsd_service
|
||||
.forward_get_request(Request::from_parts(
|
||||
parts.clone(),
|
||||
Body::from(body_bytes.clone()),
|
||||
))
|
||||
.await;
|
||||
|
||||
if let Err(e) = &forwarded_request {
|
||||
error!("Redis: failed to forward patch: {:?}", e);
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
}
|
||||
|
||||
forwarded_request
|
||||
.unwrap()
|
||||
.text()
|
||||
.await
|
||||
.unwrap()
|
||||
.into_response()
|
||||
}
|
||||
Err(error) => {
|
||||
error!("Error getting session: {:?}", error);
|
||||
StatusCode::UNAUTHORIZED.into_response()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
content_text.unwrap().into_response()
|
||||
}
|
||||
} else {
|
||||
forwarded_request.unwrap().bytes().await.unwrap().into_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_patch(
|
||||
Extension(state): Extension<Arc<AppState>>,
|
||||
request: Request<Body>,
|
||||
) -> impl IntoResponse {
|
||||
let cloned_state = state.clone();
|
||||
let (mut parts, body) = request.into_parts();
|
||||
let body_bytes = axum::body::to_bytes(body, usize::MAX).await.unwrap();
|
||||
|
||||
let mut forwarded_request = cloned_state
|
||||
.gsd_service
|
||||
.forward_patch_request(Request::from_parts(
|
||||
parts.clone(),
|
||||
Body::from(body_bytes.clone()),
|
||||
))
|
||||
.await;
|
||||
|
||||
if forwarded_request.is_err() {
|
||||
error!(
|
||||
"Failed to forward post: {:?}",
|
||||
forwarded_request.err().unwrap()
|
||||
);
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
}
|
||||
|
||||
let content_text = forwarded_request.unwrap().text().await;
|
||||
if content_text.is_err() {
|
||||
error!("Failed to read content text: {:?}", content_text.err());
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
}
|
||||
|
||||
let content = serde_json::from_str::<GSDResponseDTO>(content_text.as_ref().unwrap().as_str());
|
||||
|
||||
if content.is_err() {
|
||||
error!("Failed to read content json: {:?}", content.err());
|
||||
error!("Content: {:?}", content_text);
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
}
|
||||
|
||||
let content_unwrapped = content.unwrap();
|
||||
// Invalid session
|
||||
if content_unwrapped.status.is_some()
|
||||
&& content_unwrapped.status.unwrap().internal_status == "201"
|
||||
{
|
||||
info!("Session invalid. Re-negotiate new session");
|
||||
|
||||
match cloned_state.gsd_service.get_session().await {
|
||||
Ok(session) => {
|
||||
set_and_log_session(&cloned_state, session.clone()).await;
|
||||
|
||||
parts.headers.remove("sessionId");
|
||||
parts.headers.insert(
|
||||
"sessionId",
|
||||
HeaderValue::from_str(session.clone().as_str()).unwrap(),
|
||||
);
|
||||
|
||||
forwarded_request = cloned_state
|
||||
.gsd_service
|
||||
.forward_patch_request(Request::from_parts(
|
||||
parts.clone(),
|
||||
Body::from(body_bytes.clone()),
|
||||
))
|
||||
.await;
|
||||
|
||||
if let Err(e) = &forwarded_request {
|
||||
error!("Redis: failed to forward post: {:?}", e);
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
}
|
||||
|
||||
forwarded_request
|
||||
.unwrap()
|
||||
.text()
|
||||
.await
|
||||
.unwrap()
|
||||
.into_response()
|
||||
}
|
||||
Err(error) => {
|
||||
error!("Error getting session: {:?}", error);
|
||||
StatusCode::UNAUTHORIZED.into_response()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
content_text.unwrap().into_response()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn userinfo(request: Request<Body>) -> impl IntoResponse {
|
||||
let access_token_string = &request.headers().get("authorization").unwrap().to_str().unwrap().to_string()[7..];
|
||||
let user = decode_payload_unchecked::<User>(access_token_string).unwrap();
|
||||
|
||||
@ -16,7 +16,7 @@ pub struct GSDResponseDTO {
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GSDLoginResponseDataDTO {
|
||||
pub session_id: String,
|
||||
pub session_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||
|
||||
@ -62,10 +62,10 @@ impl GSDService {
|
||||
match response_dto.data {
|
||||
Some(data) => {
|
||||
info!(
|
||||
"Session: successfully obtained session with session id {}",
|
||||
&data.session_id
|
||||
"Session: successfully obtained session with session id {:?}",
|
||||
&data.session_id.as_ref()
|
||||
);
|
||||
Ok(data.session_id.clone())
|
||||
Ok(data.session_id.unwrap())
|
||||
}
|
||||
None => {
|
||||
error!("Session: failed to obtain session id. No session id in request found.");
|
||||
@ -89,6 +89,36 @@ impl GSDService {
|
||||
.await
|
||||
.map_err(|e| GSDServiceError::RequestError(e.to_string()))
|
||||
}
|
||||
|
||||
pub async fn forward_patch_request(
|
||||
&self,
|
||||
request: Request<Body>,
|
||||
) -> Result<Response, GSDServiceError> {
|
||||
let (parts, body) = request.into_parts();
|
||||
|
||||
reqwest::Client::new()
|
||||
.patch(format!("{}{}", self.host_url.clone(), parts.uri))
|
||||
.headers(parts.headers)
|
||||
.body(axum::body::to_bytes(body, usize::MAX).await.unwrap())
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| GSDServiceError::RequestError(e.to_string()))
|
||||
}
|
||||
|
||||
pub async fn forward_get_request(
|
||||
&self,
|
||||
request: Request<Body>,
|
||||
) -> Result<Response, GSDServiceError> {
|
||||
let (parts, body) = request.into_parts();
|
||||
|
||||
reqwest::Client::new()
|
||||
.get(format!("{}{}", self.host_url.clone(), parts.uri))
|
||||
.headers(parts.headers)
|
||||
.body(axum::body::to_bytes(body, usize::MAX).await.unwrap())
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| GSDServiceError::RequestError(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Config> for GSDService {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use crate::api::{handle_post, userinfo};
|
||||
use crate::api::{handle_get, handle_patch, handle_post, userinfo};
|
||||
use crate::config::load_config;
|
||||
use crate::middleware::AppState;
|
||||
use crate::repository::RedisRepository;
|
||||
use crate::util::initialize_logging;
|
||||
use axum::routing::{get, post};
|
||||
use axum::routing::{get, patch, post};
|
||||
use axum::{Extension, Router};
|
||||
use axum_keycloak_auth::instance::{KeycloakAuthInstance, KeycloakConfig};
|
||||
use axum_keycloak_auth::layer::KeycloakAuthLayer;
|
||||
@ -53,6 +53,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let auth_router = auth::router(state.clone());
|
||||
let proxy_router = Router::new()
|
||||
.route("/{*wildcard}", post(handle_post))
|
||||
.route("/{*wildcard}", get(handle_get))
|
||||
.route("/{*wildcard}", patch(handle_patch))
|
||||
.route("/userinfo", get(userinfo))
|
||||
.route_layer(Extension(state.clone()))
|
||||
.route_layer(axum::middleware::from_fn_with_state(
|
||||
|
||||
@ -20,14 +20,6 @@ pub struct AppState {
|
||||
pub frontend_url: String,
|
||||
}
|
||||
|
||||
pub async fn auth_middleware(
|
||||
State(_state): State<Arc<AppState>>,
|
||||
request: Request,
|
||||
next: Next,
|
||||
) -> Response {
|
||||
next.run(request).await
|
||||
}
|
||||
|
||||
/// Middleware to validate session and refresh tokens if needed
|
||||
pub async fn session_auth_middleware(
|
||||
jar: CookieJar,
|
||||
@ -131,7 +123,6 @@ pub async fn gsd_decorate_header(
|
||||
next: Next,
|
||||
) -> Response {
|
||||
let state_cloned = state.clone();
|
||||
info!("Gsd decorate header");
|
||||
|
||||
let session = state_cloned.repository.get_session().await;
|
||||
match session {
|
||||
@ -172,10 +163,6 @@ pub async fn gsd_decorate_header(
|
||||
HeaderValue::from_str(state_cloned.config.gsd_app_key.as_str()).unwrap(),
|
||||
);
|
||||
|
||||
let response = next.run(request).await;
|
||||
|
||||
info!("Response: {:?}", response);
|
||||
|
||||
response
|
||||
next.run(request).await
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user