use crate::layer::TideRequestAdapter;
use async_trait::async_trait;
use sa_token_core::StpUtil;
use sa_token_core::router::run_auth_flow;
use sa_token_plugin_common::{SaLoginId, SaTokenState, rejection};
use tide_017::{Middleware, Next, Request, Response, StatusCode};
#[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(SaLoginId(login_id));
return Ok(next.run(req).await);
}
}
}
let mut res = Response::new(StatusCode::Unauthorized);
res.set_body(rejection::unauthorized_json().to_string());
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::<SaLoginId>() {
if StpUtil::has_permission(login_id.as_str(), &self.permission).await {
return Ok(next.run(req).await);
}
}
let mut res = Response::new(StatusCode::Forbidden);
res.set_body(rejection::forbidden_json(None).to_string());
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(rejection::unauthorized_json().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(SaLoginId(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(rejection::forbidden_json(None).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(rejection::forbidden_json(None).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(SaLoginId(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(rejection::forbidden_role_json().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(rejection::forbidden_role_json().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(SaLoginId(login_id));
Ok(flow.run(next.run(req)).await)
}
}