sa_token_plugin_tide/
middleware.rs1use tide::{Middleware, Request, Response, Next, StatusCode};
7use sa_token_core::{StpUtil, error::messages, SaTokenContext, token::TokenValue};
8use async_trait::async_trait;
9use crate::state::SaTokenState;
10use crate::layer::extract_token_from_request;
11use std::sync::Arc;
12use serde_json::json;
13
14#[derive(Clone)]
27pub struct AuthMiddleware;
28
29#[async_trait]
30impl<State: Clone + Send + Sync + 'static> Middleware<State> for AuthMiddleware {
31 async fn handle(&self, mut req: Request<State>, next: Next<'_, State>) -> tide::Result {
32 let token = req
35 .header("Authorization")
36 .and_then(|v| v.as_str().strip_prefix("Bearer "))
37 .map(|s| s.to_string());
38
39 if let Some(token_str) = token {
40 use sa_token_core::TokenValue;
43 let token_value = TokenValue::from(token_str.clone());
44 if StpUtil::is_login(&token_value).await {
45 if let Ok(login_id) = StpUtil::get_login_id(&token_value).await {
48 req.set_ext(login_id);
49 return Ok(next.run(req).await);
50 }
51 }
52 }
53
54 let mut res = Response::new(StatusCode::Unauthorized);
57 res.set_body(r#"{"error":"Unauthorized"}"#);
58 res.set_content_type("application/json");
59 Ok(res)
60 }
61}
62
63#[derive(Clone)]
72pub struct PermissionMiddleware {
73 permission: String,
74}
75
76impl PermissionMiddleware {
77 pub fn new(permission: impl Into<String>) -> Self {
80 Self {
81 permission: permission.into(),
82 }
83 }
84}
85
86#[async_trait]
87impl<State: Clone + Send + Sync + 'static> Middleware<State> for PermissionMiddleware {
88 async fn handle(&self, req: Request<State>, next: Next<'_, State>) -> tide::Result {
89 if let Some(login_id) = req.ext::<String>() {
92 if StpUtil::has_permission(login_id, &self.permission).await {
95 return Ok(next.run(req).await);
96 }
97 }
98
99 let mut res = Response::new(StatusCode::Forbidden);
102 res.set_body(r#"{"error":"Forbidden"}"#);
103 res.set_content_type("application/json");
104 Ok(res)
105 }
106}
107
108#[derive(Clone)]
113pub struct SaCheckLoginMiddleware {
114 pub state: SaTokenState,
115}
116
117impl SaCheckLoginMiddleware {
118 pub fn new(state: SaTokenState) -> Self {
121 Self { state }
122 }
123}
124
125#[async_trait]
126impl<State: Clone + Send + Sync + 'static> Middleware<State> for SaCheckLoginMiddleware {
127 async fn handle(&self, mut req: Request<State>, next: Next<'_, State>) -> tide::Result {
128 let mut ctx = SaTokenContext::new();
129
130 if let Some(token_str) = extract_token_from_request(&req, &self.state.manager.config.token_name) {
131 tracing::debug!("Sa-Token(login-check): extracted token from request: {}", token_str);
132 let token = TokenValue::new(token_str);
133
134 if self.state.manager.is_valid(&token).await {
135 if let Ok(token_info) = self.state.manager.get_token_info(&token).await {
136 let login_id = token_info.login_id.clone();
137 req.set_ext(token.clone());
138 req.set_ext(login_id.clone());
139
140 ctx.token = Some(token.clone());
141 ctx.token_info = Some(Arc::new(token_info));
142 ctx.login_id = Some(login_id);
143
144 SaTokenContext::set_current(ctx);
145 let result = next.run(req).await;
146 SaTokenContext::clear();
147 return Ok(result);
148 }
149 }
150 }
151
152 let mut res = Response::new(StatusCode::Unauthorized);
154 res.set_body(json!({
155 "code": 401,
156 "message": messages::AUTH_ERROR
157 }).to_string());
158 res.set_content_type("application/json");
159 Ok(res)
160 }
161}
162
163#[derive(Clone)]
168pub struct SaCheckPermissionMiddleware {
169 pub state: SaTokenState,
170 permission: String,
171}
172
173impl SaCheckPermissionMiddleware {
174 pub fn new(state: SaTokenState, permission: impl Into<String>) -> Self {
177 Self { state, permission: permission.into() }
178 }
179}
180
181#[async_trait]
182impl<State: Clone + Send + Sync + 'static> Middleware<State> for SaCheckPermissionMiddleware {
183 async fn handle(&self, mut req: Request<State>, next: Next<'_, State>) -> tide::Result {
184 let mut ctx = SaTokenContext::new();
185
186 if let Some(token_str) = extract_token_from_request(&req, &self.state.manager.config.token_name) {
187 tracing::debug!("Sa-Token(permission-check): extracted token from request: {}", token_str);
188 let token = TokenValue::new(token_str);
189
190 if self.state.manager.is_valid(&token).await {
191 if let Ok(token_info) = self.state.manager.get_token_info(&token).await {
192 let login_id = token_info.login_id.clone();
193
194 if StpUtil::has_permission(&login_id, &self.permission).await {
196 req.set_ext(token.clone());
197 req.set_ext(login_id.clone());
198
199 ctx.token = Some(token.clone());
200 ctx.token_info = Some(Arc::new(token_info));
201 ctx.login_id = Some(login_id);
202
203 SaTokenContext::set_current(ctx);
204 let result = next.run(req).await;
205 SaTokenContext::clear();
206 return Ok(result);
207 }
208 }
209 }
210 }
211
212 let mut res = Response::new(StatusCode::Forbidden);
214 res.set_body(json!({
215 "code": 403,
216 "message": messages::PERMISSION_REQUIRED
217 }).to_string());
218 res.set_content_type("application/json");
219 Ok(res)
220 }
221}
222
223#[derive(Clone)]
228pub struct SaCheckRoleMiddleware {
229 pub state: SaTokenState,
230 role: String,
231}
232
233impl SaCheckRoleMiddleware {
234 pub fn new(state: SaTokenState, role: impl Into<String>) -> Self {
237 Self { state, role: role.into() }
238 }
239}
240
241#[async_trait]
242impl<State: Clone + Send + Sync + 'static> Middleware<State> for SaCheckRoleMiddleware {
243 async fn handle(&self, mut req: Request<State>, next: Next<'_, State>) -> tide::Result {
244 let mut ctx = SaTokenContext::new();
245
246 if let Some(token_str) = extract_token_from_request(&req, &self.state.manager.config.token_name) {
247 tracing::debug!("Sa-Token(role-check): extracted token from request: {}", token_str);
248 let token = TokenValue::new(token_str);
249
250 if self.state.manager.is_valid(&token).await {
251 if let Ok(token_info) = self.state.manager.get_token_info(&token).await {
252 let login_id = token_info.login_id.clone();
253
254 if StpUtil::has_role(&login_id, &self.role).await {
256 req.set_ext(token.clone());
257 req.set_ext(login_id.clone());
258
259 ctx.token = Some(token.clone());
260 ctx.token_info = Some(Arc::new(token_info));
261 ctx.login_id = Some(login_id);
262
263 SaTokenContext::set_current(ctx);
264 let result = next.run(req).await;
265 SaTokenContext::clear();
266 return Ok(result);
267 }
268 }
269 }
270 }
271
272 let mut res = Response::new(StatusCode::Forbidden);
274 res.set_body(json!({
275 "code": 403,
276 "message": messages::ROLE_REQUIRED
277 }).to_string());
278 res.set_content_type("application/json");
279 Ok(res)
280 }
281}