spring_sa_token/configurator.rs
1//! Sa-Token Configurator module
2//!
3//! This module provides a Spring Security-like configuration mechanism
4//! for path-based authentication.
5//!
6//! # Example
7//!
8//! Define your security configuration in a separate file:
9//!
10//! ```rust,ignore
11//! // security.rs
12//! use spring_sa_token::{PathAuthBuilder, SaTokenConfigurator};
13//!
14//! pub struct SecurityConfig;
15//!
16//! impl SaTokenConfigurator for SecurityConfig {
17//! fn configure(&self, auth: PathAuthBuilder) -> PathAuthBuilder {
18//! auth.include("/user/**")
19//! .include("/admin/**")
20//! .exclude("/login")
21//! .exclude("/public/**")
22//! }
23//! }
24//! ```
25//!
26//! Then use it in main.rs:
27//!
28//! ```rust,ignore
29//! // main.rs
30//! mod security;
31//! use spring_sa_token::SaTokenAuthConfigurator;
32//!
33//! App::new()
34//! .add_plugin(RedisPlugin)
35//! .add_plugin(SaTokenPlugin)
36//! .add_plugin(WebPlugin)
37//! .sa_token_auth(security::SecurityConfig)
38//! .run()
39//! .await
40//! ```
41
42use sa_token_core::router::PathAuthConfig;
43use spring::app::AppBuilder;
44use spring::plugin::MutableComponentRegistry;
45
46/// Trait for configuring Sa-Token path-based authentication
47///
48/// Implement this trait to define your security configuration,
49/// similar to Spring Security's configuration classes.
50///
51/// # Example
52///
53/// ```rust,ignore
54/// use spring_sa_token::{PathAuthBuilder, SaTokenConfigurator};
55///
56/// pub struct SecurityConfig;
57///
58/// impl SaTokenConfigurator for SecurityConfig {
59/// fn configure(&self, auth: PathAuthBuilder) -> PathAuthBuilder {
60/// auth.include("/api/**")
61/// .include("/user/**")
62/// .exclude("/login")
63/// .exclude("/public/**")
64/// }
65/// }
66/// ```
67pub trait SaTokenConfigurator: Send + Sync + 'static {
68 /// Configure path-based authentication rules
69 ///
70 /// Receives a PathAuthBuilder and should return it with your rules applied.
71 fn configure(&self, auth: PathAuthBuilder) -> PathAuthBuilder;
72}
73
74/// Builder for path-based authentication configuration
75///
76/// Provides a fluent API for configuring which paths require authentication.
77///
78/// # Supported Patterns (Ant-style)
79///
80/// - `/**` - Match all paths
81/// - `/api/**` - Match all paths starting with `/api/`
82/// - `/api/*` - Match single-level paths under `/api/` (not nested)
83/// - `*.html` - Match paths ending with `.html`
84/// - `/exact` - Exact match
85///
86/// # Example
87///
88/// ```rust,ignore
89/// let config = PathAuthBuilder::new()
90/// .include("/api/**")
91/// .include("/user/**")
92/// .exclude("/login")
93/// .exclude("/register")
94/// .build();
95/// ```
96#[derive(Debug, Clone, Default)]
97pub struct PathAuthBuilder {
98 pub include: Vec<String>,
99 pub exclude: Vec<String>,
100}
101
102impl PathAuthBuilder {
103 /// Create a new PathAuthBuilder
104 pub fn new() -> Self {
105 Self::default()
106 }
107
108 /// Add a path pattern that requires authentication
109 ///
110 /// # Example
111 ///
112 /// ```rust,ignore
113 /// auth.include("/api/**") // All paths under /api/ require auth
114 /// ```
115 pub fn include(mut self, pattern: impl Into<String>) -> Self {
116 self.include.push(pattern.into());
117 self
118 }
119
120 /// Add multiple path patterns that require authentication
121 ///
122 /// # Example
123 ///
124 /// ```rust,ignore
125 /// auth.include_all(["/api/**", "/user/**", "/admin/**"])
126 /// ```
127 pub fn include_all(mut self, patterns: impl IntoIterator<Item = impl Into<String>>) -> Self {
128 self.include.extend(patterns.into_iter().map(|p| p.into()));
129 self
130 }
131
132 /// Add a path pattern that is excluded from authentication
133 ///
134 /// # Example
135 ///
136 /// ```rust,ignore
137 /// auth.exclude("/login") // /login doesn't require auth
138 /// ```
139 pub fn exclude(mut self, pattern: impl Into<String>) -> Self {
140 self.exclude.push(pattern.into());
141 self
142 }
143
144 /// Add multiple path patterns that are excluded from authentication
145 ///
146 /// # Example
147 ///
148 /// ```rust,ignore
149 /// auth.exclude_all(["/login", "/register", "/public/**"])
150 /// ```
151 pub fn exclude_all(mut self, patterns: impl IntoIterator<Item = impl Into<String>>) -> Self {
152 self.exclude.extend(patterns.into_iter().map(|p| p.into()));
153 self
154 }
155
156 /// Alias for `exclude` - paths that don't require authentication (permit all)
157 ///
158 /// Named similarly to Spring Security's `permitAll()`
159 pub fn permit_all(self, pattern: impl Into<String>) -> Self {
160 self.exclude(pattern)
161 }
162
163 /// Alias for `include` - paths that require authentication
164 ///
165 /// Named similarly to Spring Security's `authenticated()`
166 pub fn authenticated(self, pattern: impl Into<String>) -> Self {
167 self.include(pattern)
168 }
169
170 /// Check if any include patterns are configured
171 pub fn is_configured(&self) -> bool {
172 !self.include.is_empty()
173 }
174
175 /// Build the final PathAuthConfig
176 pub fn build(self) -> PathAuthConfig {
177 PathAuthConfig::new()
178 .include(self.include)
179 .exclude(self.exclude)
180 }
181
182 /// Merge another builder's rules into this one
183 pub fn merge(mut self, other: PathAuthBuilder) -> Self {
184 self.include.extend(other.include);
185 self.exclude.extend(other.exclude);
186 self
187 }
188}
189
190// ============================================================================
191// SaTokenAuthConfigurator - Fluent API for configuring path-based auth
192// ============================================================================
193
194/// Trait for configuring Sa-Token path-based authentication via AppBuilder
195///
196/// This provides a fluent API to configure authentication directly on the App.
197///
198/// # Example
199///
200/// Define your security configuration in a separate file:
201///
202/// ```rust,ignore
203/// // security.rs
204/// use spring_sa_token::{PathAuthBuilder, SaTokenConfigurator};
205///
206/// pub struct SecurityConfig;
207///
208/// impl SaTokenConfigurator for SecurityConfig {
209/// fn configure(&self, auth: PathAuthBuilder) -> PathAuthBuilder {
210/// auth.include("/user/**")
211/// .include("/admin/**")
212/// .include("/api/**")
213/// .exclude("/")
214/// .exclude("/login")
215/// .exclude("/public/**")
216/// .exclude("/api/health")
217/// }
218/// }
219/// ```
220///
221/// Then use it in main.rs:
222///
223/// ```rust,ignore
224/// // main.rs
225/// mod security;
226/// use spring_sa_token::SaTokenAuthConfigurator;
227///
228/// App::new()
229/// .add_plugin(RedisPlugin)
230/// .add_plugin(SaTokenPlugin)
231/// .add_plugin(WebPlugin)
232/// .sa_token_auth(security::SecurityConfig)
233/// .run()
234/// .await
235/// ```
236pub trait SaTokenAuthConfigurator {
237 /// Configure path-based authentication rules using a SaTokenConfigurator implementation
238 ///
239 /// # Example
240 ///
241 /// ```rust,ignore
242 /// app.sa_token_auth(SecurityConfig);
243 /// ```
244 fn sa_token_auth<C>(&mut self, configurator: C) -> &mut Self
245 where
246 C: SaTokenConfigurator;
247}
248
249impl SaTokenAuthConfigurator for AppBuilder {
250 fn sa_token_auth<C>(&mut self, configurator: C) -> &mut Self
251 where
252 C: SaTokenConfigurator ,
253 {
254 let builder = configurator.configure(PathAuthBuilder::new());
255 if builder.is_configured() {
256 let config = builder.build();
257 self.add_component(config)
258 } else {
259 self
260 }
261 }
262}
263
264impl SaTokenConfigurator for PathAuthBuilder {
265 fn configure(&self, auth: PathAuthBuilder) -> PathAuthBuilder {
266 auth.merge(self.clone())
267 }
268}