feat(saas): Phase 1 — 基础框架与账号管理模块
- 新增 zclaw-saas crate 作为 workspace 成员 - 配置系统 (TOML + 环境变量覆盖) - 错误类型体系 (SaasError 16 变体, IntoResponse) - SQLite 数据库 (12 表 schema, 内存/文件双模式, 3 系统角色种子数据) - JWT 认证 (签发/验证/刷新) - Argon2id 密码哈希 - 认证中间件 (公开/受保护路由分层) - 账号管理 CRUD + API Token 管理 + 操作日志 - 7 单元测试 + 5 集成测试全部通过
This commit is contained in:
69
crates/zclaw-saas/src/auth/mod.rs
Normal file
69
crates/zclaw-saas/src/auth/mod.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
//! 认证模块
|
||||
|
||||
pub mod jwt;
|
||||
pub mod password;
|
||||
pub mod types;
|
||||
pub mod handlers;
|
||||
|
||||
use axum::{
|
||||
extract::{Request, State},
|
||||
http::header,
|
||||
middleware::Next,
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use secrecy::ExposeSecret;
|
||||
use crate::error::SaasError;
|
||||
use crate::state::AppState;
|
||||
use types::AuthContext;
|
||||
|
||||
/// 认证中间件: 从 JWT 或 API Token 提取身份
|
||||
pub async fn auth_middleware(
|
||||
State(state): State<AppState>,
|
||||
mut req: Request,
|
||||
next: Next,
|
||||
) -> Response {
|
||||
let auth_header = req.headers()
|
||||
.get(header::AUTHORIZATION)
|
||||
.and_then(|v| v.to_str().ok());
|
||||
|
||||
let result = if let Some(auth) = auth_header {
|
||||
if let Some(token) = auth.strip_prefix("Bearer ") {
|
||||
jwt::verify_token(token, state.jwt_secret.expose_secret())
|
||||
.map(|claims| AuthContext {
|
||||
account_id: claims.sub,
|
||||
role: claims.role,
|
||||
permissions: claims.permissions,
|
||||
})
|
||||
.map_err(|_| SaasError::Unauthorized)
|
||||
} else {
|
||||
Err(SaasError::Unauthorized)
|
||||
}
|
||||
} else {
|
||||
Err(SaasError::Unauthorized)
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(ctx) => {
|
||||
req.extensions_mut().insert(ctx);
|
||||
next.run(req).await
|
||||
}
|
||||
Err(e) => e.into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 路由 (无需认证的端点)
|
||||
pub fn routes() -> axum::Router<AppState> {
|
||||
use axum::routing::post;
|
||||
|
||||
axum::Router::new()
|
||||
.route("/api/v1/auth/register", post(handlers::register))
|
||||
.route("/api/v1/auth/login", post(handlers::login))
|
||||
}
|
||||
|
||||
/// 需要认证的路由
|
||||
pub fn protected_routes() -> axum::Router<AppState> {
|
||||
use axum::routing::post;
|
||||
|
||||
axum::Router::new()
|
||||
.route("/api/v1/auth/refresh", post(handlers::refresh))
|
||||
}
|
||||
Reference in New Issue
Block a user