sa_token_plugin_tide/
middleware.rs

1// Author: 金书记
2//
3// 中文 | English
4// Tide 认证中间件 | Tide authentication middleware
5
6use 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/// 中文 | English
15/// 认证中间件 - 验证用户登录状态 | Authentication middleware - verify user login status
16///
17/// # 示例 | Example
18/// ```rust,ignore
19/// use tide::prelude::*;
20/// use sa_token_plugin_tide::AuthMiddleware;
21///
22/// let mut app = tide::new();
23/// app.with(AuthMiddleware);
24/// app.at("/user").get(user_handler);
25/// ```
26#[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        // 中文 | English
33        // 从请求头中获取 token | Get token from request headers
34        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            // 中文 | English
41            // 验证 token 是否有效 | Verify if token is valid
42            use sa_token_core::TokenValue;
43            let token_value = TokenValue::from(token_str.clone());
44            if StpUtil::is_login(&token_value).await {
45                // 中文 | English
46                // Token 有效,将 login_id 存入扩展数据 | Token valid, store login_id in extensions
47                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        // 中文 | English
55        // Token 无效,返回 401 | Token invalid, return 401
56        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/// 中文 | English
64/// 权限验证中间件 - 验证用户是否拥有指定权限 | Permission middleware - verify if user has specified permissions
65///
66/// # 示例 | Example
67/// ```rust,ignore
68/// let mut app = tide::new();
69/// app.with(PermissionMiddleware::new("user:read"));
70/// ```
71#[derive(Clone)]
72pub struct PermissionMiddleware {
73    permission: String,
74}
75
76impl PermissionMiddleware {
77    /// 中文 | English
78    /// 创建权限验证中间件 | Create permission middleware
79    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        // 中文 | English
90        // 从扩展数据获取 login_id | Get login_id from extensions
91        if let Some(login_id) = req.ext::<String>() {
92            // 中文 | English
93            // 验证权限 | Verify permission
94            if StpUtil::has_permission(login_id, &self.permission).await {
95                return Ok(next.run(req).await);
96            }
97        }
98        
99        // 中文 | English
100        // 无权限,返回 403 | No permission, return 403
101        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/// 中文 | English
109/// Sa-Token 登录检查中间件 | Sa-Token login check middleware
110///
111/// 使用标准错误消息,检查当前请求是否已登录 | Uses standard error messages, checks if current request is logged in
112#[derive(Clone)]
113pub struct SaCheckLoginMiddleware {
114    pub state: SaTokenState,
115}
116
117impl SaCheckLoginMiddleware {
118    /// 中文 | English
119    /// 创建新的登录检查中间件 | Create new login check middleware
120    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        // 未登录,返回401错误
153        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/// 中文 | English
164/// Sa-Token 权限检查中间件 | Sa-Token permission check middleware
165///
166/// 检查当前请求用户是否拥有指定权限 | Checks if current request user has specified permission
167#[derive(Clone)]
168pub struct SaCheckPermissionMiddleware {
169    pub state: SaTokenState,
170    permission: String,
171}
172
173impl SaCheckPermissionMiddleware {
174    /// 中文 | English
175    /// 创建新的权限检查中间件 | Create new permission check middleware
176    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                    // 检查权限
195                    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        // 无权限,返回403错误
213        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/// 中文 | English
224/// Sa-Token 角色检查中间件 | Sa-Token role check middleware
225///
226/// 检查当前请求用户是否拥有指定角色 | Checks if current request user has specified role
227#[derive(Clone)]
228pub struct SaCheckRoleMiddleware {
229    pub state: SaTokenState,
230    role: String,
231}
232
233impl SaCheckRoleMiddleware {
234    /// 中文 | English
235    /// 创建新的角色检查中间件 | Create new role check middleware
236    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                    // 检查角色
255                    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        // 无角色权限,返回403错误
273        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}