feat(sso): sso login

This commit is contained in:
2026-02-03 17:31:56 +08:00
parent 2ddc11eb7b
commit a11c742e70
7 changed files with 39 additions and 21 deletions

View File

@@ -13,6 +13,7 @@ use crate::api::AppState;
#[derive(Debug, Deserialize)]
pub struct CallbackQuery {
pub code: String,
pub tenant_id: Option<String>,
pub next: Option<String>,
}
@@ -30,7 +31,6 @@ struct Code2TokenData {
access_token: String,
refresh_token: String,
expires_in: usize,
token_type: String,
tenant_id: String,
user_id: String,
}
@@ -121,6 +121,17 @@ async fn sso_callback_handler(
return Ok(Redirect::temporary(&target).into_response());
}
let tenant_id = q
.tenant_id
.as_deref()
.unwrap_or("")
.trim()
.to_string();
if uuid::Uuid::parse_str(&tenant_id).is_err() {
let target = resolve_front_error_redirect("missing or invalid tenant_id");
return Ok(Redirect::temporary(&target).into_response());
}
let iam_base = std::env::var("IAM_BASE_URL")
.or_else(|_| std::env::var("IAM_SERVICE_BASE_URL"))
.map_err(|_| AppError::ConfigError("IAM_BASE_URL is required".into()))?;
@@ -132,9 +143,10 @@ async fn sso_callback_handler(
let http = reqwest::Client::new();
let resp = http
.post(format!(
"{}/iam/api/v1/auth/code2token",
"{}/api/v1/auth/code2token",
iam_base.trim_end_matches('/')
))
.header("X-Tenant-ID", tenant_id)
.json(&Code2TokenRequest {
code: q.code,
client_id,

View File

@@ -29,7 +29,7 @@ pub fn build_router(state: AppState) -> Router {
.nest("/media", handlers::media::router())
.nest("/articles", handlers::article::router());
let app = Router::new()
Router::new()
.route("/favicon.ico", get(|| async { axum::http::StatusCode::NO_CONTENT }))
.merge(Scalar::with_url("/scalar", ApiDoc::openapi()))
.merge(health)
@@ -37,7 +37,5 @@ pub fn build_router(state: AppState) -> Router {
.nest("/v1", v1)
.layer(axum::middleware::from_fn(catch_panic))
.layer(axum::middleware::from_fn(request_logger))
.with_state(state);
app
.with_state(state)
}

View File

@@ -47,6 +47,7 @@ impl CmsServices {
repositories::column::get_column(&self.pool, tenant_id, id).await
}
#[allow(clippy::too_many_arguments)]
pub async fn update_column(
&self,
tenant_id: Uuid,
@@ -110,6 +111,7 @@ impl CmsServices {
repositories::tag::delete_tag(&self.pool, tenant_id, id).await
}
#[allow(clippy::too_many_arguments)]
pub async fn create_media(
&self,
tenant_id: Uuid,
@@ -149,6 +151,7 @@ impl CmsServices {
repositories::media::delete_media(&self.pool, tenant_id, id).await
}
#[allow(clippy::too_many_arguments)]
pub async fn create_article(
&self,
tenant_id: Uuid,
@@ -190,6 +193,7 @@ impl CmsServices {
repositories::article::list_articles(&self.pool, tenant_id, q).await
}
#[allow(clippy::too_many_arguments)]
pub async fn update_article(
&self,
tenant_id: Uuid,

View File

@@ -125,10 +125,10 @@ impl IamClient {
};
let now = Instant::now();
if let Some(entry) = self.inner.cache.get(&key).map(|e| e.clone()) {
if entry.expires_at > now {
return Ok(entry.allowed);
}
if let Some(entry) = self.inner.cache.get(&key).map(|e| e.clone())
&& entry.expires_at > now
{
return Ok(entry.allowed);
}
let remote = self
@@ -141,17 +141,17 @@ impl IamClient {
Ok(allowed)
}
Err(e) => {
if let Some(entry) = self.inner.cache.get(&key).map(|e| e.clone()) {
if entry.stale_until > now {
tracing::warn!(
tenant_id = %tenant_id,
user_id = %user_id,
action = "iam_client.degraded_cache",
latency_ms = 0_u64,
error_code = "iam_degraded_cache"
);
return Ok(entry.allowed);
}
if let Some(entry) = self.inner.cache.get(&key).map(|e| e.clone())
&& entry.stale_until > now
{
tracing::warn!(
tenant_id = %tenant_id,
user_id = %user_id,
action = "iam_client.degraded_cache",
latency_ms = 0_u64,
error_code = "iam_degraded_cache"
);
return Ok(entry.allowed);
}
Err(e)
}

View File

@@ -29,6 +29,7 @@ async fn list_tag_ids_for_article(
Ok(tags)
}
#[allow(clippy::too_many_arguments)]
pub async fn create_article(
pool: &PgPool,
tenant_id: Uuid,
@@ -109,6 +110,7 @@ pub async fn get_article(
Ok(ArticleWithTags { article, tag_ids })
}
#[allow(clippy::too_many_arguments)]
pub async fn update_article(
pool: &PgPool,
tenant_id: Uuid,

View File

@@ -47,6 +47,7 @@ pub async fn get_column(pool: &PgPool, tenant_id: Uuid, id: Uuid) -> Result<Colu
Ok(column)
}
#[allow(clippy::too_many_arguments)]
pub async fn update_column(
pool: &PgPool,
tenant_id: Uuid,

View File

@@ -3,6 +3,7 @@ use common_telemetry::AppError;
use sqlx::PgPool;
use uuid::Uuid;
#[allow(clippy::too_many_arguments)]
pub async fn create_media(
pool: &PgPool,
tenant_id: Uuid,