use tide_017::{Middleware, Request, Response, Next, StatusCode};
use sa_token_core::{StpUtil, error::messages};
use sa_token_core::router::run_auth_flow;
use async_trait::async_trait;
use crate::state::SaTokenState;
use crate::layer::TideRequestAdapter;
use serde_json::json;
#[derive(Clone)]
pub struct AuthMiddleware;
#[async_trait]
impl<State: Clone + Send + Sync + 'static> Middleware<State> for AuthMiddleware {
async fn handle(&self, mut req: Request<State>, next: Next<'_, State>) -> tide_017::Result {
let token = req
.header("Authorization")
.and_then(|v| v.as_str().strip_prefix("Bearer "))
.map(|s| s.to_string());
if let Some(token_str) = token {
use sa_token_core::TokenValue;
let token_value = TokenValue::from(token_str.clone());
if StpUtil::is_login(&token_value).await {
if let Ok(login_id) = StpUtil::get_login_id(&token_value).await {
req.set_ext(login_id);
return Ok(next.run(req).await);
}
}
}
let mut res = Response::new(StatusCode::Unauthorized);
res.set_body(r#"{"error":"Unauthorized"}"#);
res.set_content_type("application/json");
Ok(res)
}
}
#[derive(Clone)]
pub struct PermissionMiddleware {
permission: String,
}
impl PermissionMiddleware {
pub fn new(permission: impl Into<String>) -> Self {
Self {
permission: permission.into(),
}
}
}
#[async_trait]
impl<State: Clone + Send + Sync + 'static> Middleware<State> for PermissionMiddleware {
async fn handle(&self, req: Request<State>, next: Next<'_, State>) -> tide_017::Result {
if let Some(login_id) = req.ext::<String>() {
if StpUtil::has_permission(login_id, &self.permission).await {
return Ok(next.run(req).await);
}
}
let mut res = Response::new(StatusCode::Forbidden);
res.set_body(r#"{"error":"Forbidden"}"#);
res.set_content_type("application/json");
Ok(res)
}
}
#[derive(Clone)]
pub struct SaCheckLoginMiddleware {
pub state: SaTokenState,
}
impl SaCheckLoginMiddleware {
pub fn new(state: SaTokenState) -> Self {
Self { state }
}
}
#[async_trait]
impl<State: Clone + Send + Sync + 'static> Middleware<State> for SaCheckLoginMiddleware {
async fn handle(&self, mut req: Request<State>, next: Next<'_, State>) -> tide_017::Result {
let adapter = TideRequestAdapter::new(&req);
let flow = run_auth_flow(&adapter, &self.state.manager, None).await;
if flow.token.is_none() || flow.login_id.is_none() {
let mut res = Response::new(StatusCode::Unauthorized);
res.set_body(json!({
"code": 401,
"message": messages::AUTH_ERROR
}).to_string());
res.set_content_type("application/json");
return Ok(res);
}
if let Some(t) = &flow.token {
req.set_ext(t.clone());
}
if let Some(id) = &flow.login_id {
req.set_ext(id.clone());
}
Ok(flow.run(next.run(req)).await)
}
}
#[derive(Clone)]
pub struct SaCheckPermissionMiddleware {
pub state: SaTokenState,
permission: String,
}
impl SaCheckPermissionMiddleware {
pub fn new(state: SaTokenState, permission: impl Into<String>) -> Self {
Self { state, permission: permission.into() }
}
}
#[async_trait]
impl<State: Clone + Send + Sync + 'static> Middleware<State> for SaCheckPermissionMiddleware {
async fn handle(&self, mut req: Request<State>, next: Next<'_, State>) -> tide_017::Result {
let adapter = TideRequestAdapter::new(&req);
let flow = run_auth_flow(&adapter, &self.state.manager, None).await;
let Some(login_id) = flow.login_id.clone() else {
let mut res = Response::new(StatusCode::Forbidden);
res.set_body(json!({
"code": 403,
"message": messages::PERMISSION_REQUIRED
}).to_string());
res.set_content_type("application/json");
return Ok(res);
};
if !StpUtil::has_permission(&login_id, &self.permission).await {
let mut res = Response::new(StatusCode::Forbidden);
res.set_body(json!({
"code": 403,
"message": messages::PERMISSION_REQUIRED
}).to_string());
res.set_content_type("application/json");
return Ok(res);
}
if let Some(t) = &flow.token {
req.set_ext(t.clone());
}
req.set_ext(login_id);
Ok(flow.run(next.run(req)).await)
}
}
#[derive(Clone)]
pub struct SaCheckRoleMiddleware {
pub state: SaTokenState,
role: String,
}
impl SaCheckRoleMiddleware {
pub fn new(state: SaTokenState, role: impl Into<String>) -> Self {
Self { state, role: role.into() }
}
}
#[async_trait]
impl<State: Clone + Send + Sync + 'static> Middleware<State> for SaCheckRoleMiddleware {
async fn handle(&self, mut req: Request<State>, next: Next<'_, State>) -> tide_017::Result {
let adapter = TideRequestAdapter::new(&req);
let flow = run_auth_flow(&adapter, &self.state.manager, None).await;
let Some(login_id) = flow.login_id.clone() else {
let mut res = Response::new(StatusCode::Forbidden);
res.set_body(json!({
"code": 403,
"message": messages::ROLE_REQUIRED
}).to_string());
res.set_content_type("application/json");
return Ok(res);
};
if !StpUtil::has_role(&login_id, &self.role).await {
let mut res = Response::new(StatusCode::Forbidden);
res.set_body(json!({
"code": 403,
"message": messages::ROLE_REQUIRED
}).to_string());
res.set_content_type("application/json");
return Ok(res);
}
if let Some(t) = &flow.token {
req.set_ext(t.clone());
}
req.set_ext(login_id);
Ok(flow.run(next.run(req)).await)
}
}