summer_sa_token/configurator.rs
1//! Sa-Token Configurator module
2//!
3//! This module provides a summer 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//! // config.rs
12//! use summer_sa_token::{PathAuthBuilder, SaTokenConfigurator};
13//!
14//! pub struct SaTokenConfig;
15//!
16//! impl SaTokenConfigurator for SaTokenConfig {
17//! fn configure_path_auth(&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 config;
31//! use summer_sa_token::SaTokenAuthConfigurator;
32//!
33//! App::new()
34//! .add_plugin(RedisPlugin)
35//! .add_plugin(SaTokenPlugin)
36//! .add_plugin(WebPlugin)
37//! .sa_token_configure(config::SaTokenConfig)
38//! .run()
39//! .await
40//! ```
41
42use sa_token_adapter::storage::SaStorage;
43use sa_token_core::router::PathAuthConfig;
44use summer::app::AppBuilder;
45use summer::plugin::MutableComponentRegistry;
46use std::sync::Arc;
47
48/// Trait for configuring Sa-Token path-based authentication
49///
50/// Implement this trait to define your security configuration,
51/// similar to summer Security's configuration classes.
52///
53/// # Example
54///
55/// ```rust,ignore
56/// use summer_sa_token::{PathAuthBuilder, SaTokenConfigurator};
57///
58/// pub struct SaTokenConfig;
59///
60/// impl SaTokenConfigurator for SaTokenConfig {
61/// fn configure_path_auth(&self, auth: PathAuthBuilder) -> PathAuthBuilder {
62/// auth.include("/api/**")
63/// .include("/user/**")
64/// .exclude("/login")
65/// .exclude("/public/**")
66/// }
67/// }
68/// ```
69pub trait SaTokenConfigurator: Send + Sync + 'static {
70 /// Configure path-based authentication rules (legacy).
71 ///
72 /// Prefer implementing [`SaTokenConfigurator::configure_path_auth`].
73 #[deprecated(note = "use `configure_path_auth` instead")]
74 fn configure(&self, auth: PathAuthBuilder) -> PathAuthBuilder {
75 auth
76 }
77
78 /// Configure path-based authentication rules.
79 ///
80 /// Receives a [`PathAuthBuilder`] and should return it with your rules applied.
81 ///
82 /// By default, this falls back to the legacy [`SaTokenConfigurator::configure`] method,
83 /// so existing implementations keep working.
84 fn configure_path_auth(&self, auth: PathAuthBuilder) -> PathAuthBuilder {
85 #[allow(deprecated)]
86 self.configure(auth)
87 }
88
89 /// Optional hook to provide a custom token storage implementation.
90 ///
91 /// If this returns `Some(storage)`, `summer-sa-token` will register it as a component
92 /// (`Arc<dyn SaStorage>`), and the Sa-Token plugin will prefer it over built-in storages
93 /// (e.g. redis/memory).
94 ///
95 /// Default: `None` (use built-in storage selection).
96 fn configure_storage(&self, _app: &AppBuilder) -> Option<Arc<dyn SaStorage>> {
97 None
98 }
99}
100
101/// Builder for path-based authentication configuration
102///
103/// Provides a fluent API for configuring which paths require authentication.
104///
105/// # Supported Patterns (Ant-style)
106///
107/// - `/**` - Match all paths
108/// - `/api/**` - Match all paths starting with `/api/`
109/// - `/api/*` - Match single-level paths under `/api/` (not nested)
110/// - `*.html` - Match paths ending with `.html`
111/// - `/exact` - Exact match
112///
113/// # Example
114///
115/// ```rust,ignore
116/// let config = PathAuthBuilder::new()
117/// .include("/api/**")
118/// .include("/user/**")
119/// .exclude("/login")
120/// .exclude("/register")
121/// .build();
122/// ```
123#[derive(Debug, Clone, Default)]
124pub struct PathAuthBuilder {
125 pub include: Vec<String>,
126 pub exclude: Vec<String>,
127}
128
129impl PathAuthBuilder {
130 /// Create a new PathAuthBuilder
131 pub fn new() -> Self {
132 Self::default()
133 }
134
135 /// Add a path pattern that requires authentication
136 ///
137 /// # Example
138 ///
139 /// ```rust,ignore
140 /// auth.include("/api/**") // All paths under /api/ require auth
141 /// ```
142 pub fn include(mut self, pattern: impl Into<String>) -> Self {
143 self.include.push(pattern.into());
144 self
145 }
146
147 /// Add multiple path patterns that require authentication
148 ///
149 /// # Example
150 ///
151 /// ```rust,ignore
152 /// auth.include_all(["/api/**", "/user/**", "/admin/**"])
153 /// ```
154 pub fn include_all(mut self, patterns: impl IntoIterator<Item = impl Into<String>>) -> Self {
155 self.include.extend(patterns.into_iter().map(|p| p.into()));
156 self
157 }
158
159 /// Add a path pattern that is excluded from authentication
160 ///
161 /// # Example
162 ///
163 /// ```rust,ignore
164 /// auth.exclude("/login") // /login doesn't require auth
165 /// ```
166 pub fn exclude(mut self, pattern: impl Into<String>) -> Self {
167 self.exclude.push(pattern.into());
168 self
169 }
170
171 /// Add multiple path patterns that are excluded from authentication
172 ///
173 /// # Example
174 ///
175 /// ```rust,ignore
176 /// auth.exclude_all(["/login", "/register", "/public/**"])
177 /// ```
178 pub fn exclude_all(mut self, patterns: impl IntoIterator<Item = impl Into<String>>) -> Self {
179 self.exclude.extend(patterns.into_iter().map(|p| p.into()));
180 self
181 }
182
183 /// Alias for `exclude` - paths that don't require authentication (permit all)
184 ///
185 /// Named similarly to summer Security's `permitAll()`
186 pub fn permit_all(self, pattern: impl Into<String>) -> Self {
187 self.exclude(pattern)
188 }
189
190 /// Alias for `include` - paths that require authentication
191 ///
192 /// Named similarly to summer Security's `authenticated()`
193 pub fn authenticated(self, pattern: impl Into<String>) -> Self {
194 self.include(pattern)
195 }
196
197 /// Check if any include patterns are configured
198 pub fn is_configured(&self) -> bool {
199 !self.include.is_empty()
200 }
201
202 /// Build the final PathAuthConfig
203 pub fn build(self) -> PathAuthConfig {
204 PathAuthConfig::new()
205 .include(self.include)
206 .exclude(self.exclude)
207 }
208
209 /// Merge another builder's rules into this one
210 pub fn merge(mut self, other: PathAuthBuilder) -> Self {
211 self.include.extend(other.include);
212 self.exclude.extend(other.exclude);
213 self
214 }
215}
216
217// ============================================================================
218// SaTokenAuthConfigurator - Fluent API for configuring path-based auth
219// ============================================================================
220
221/// Trait for configuring Sa-Token path-based authentication via AppBuilder
222///
223/// This provides a fluent API to configure authentication directly on the App.
224///
225/// # Example
226///
227/// Define your security configuration in a separate file:
228///
229/// ```rust,ignore
230/// // config.rs
231/// use summer_sa_token::{PathAuthBuilder, SaTokenConfigurator};
232///
233/// pub struct SaTokenConfig;
234///
235/// impl SaTokenConfigurator for SaTokenConfig {
236/// fn configure_path_auth(&self, auth: PathAuthBuilder) -> PathAuthBuilder {
237/// auth.include("/user/**")
238/// .include("/admin/**")
239/// .include("/api/**")
240/// .exclude("/")
241/// .exclude("/login")
242/// .exclude("/public/**")
243/// .exclude("/api/health")
244/// }
245/// }
246/// ```
247///
248/// Then use it in main.rs:
249///
250/// ```rust,ignore
251/// // main.rs
252/// mod config;
253/// use summer_sa_token::SaTokenAuthConfigurator;
254///
255/// App::new()
256/// .add_plugin(RedisPlugin)
257/// .add_plugin(SaTokenPlugin)
258/// .add_plugin(WebPlugin)
259/// .sa_token_configure(config::SaTokenConfig)
260/// .run()
261/// .await
262/// ```
263pub trait SaTokenAuthConfigurator {
264 /// Configure path-based authentication rules using a SaTokenConfigurator implementation
265 ///
266 /// # Example
267 ///
268 /// ```rust,ignore
269 /// app.sa_token_configure(config::SaTokenConfig);
270 /// ```
271 #[deprecated(note = "use `sa_token_configure` instead")]
272 fn sa_token_auth<C>(&mut self, configurator: C) -> &mut Self
273 where
274 C: SaTokenConfigurator;
275
276 /// Configure path-based authentication rules using a SaTokenConfigurator implementation
277 ///
278 /// # Example
279 ///
280 /// ```rust,ignore
281 /// app.sa_token_configure(config::SaTokenConfig);
282 /// ```
283 fn sa_token_configure<C>(&mut self, configurator: C) -> &mut Self
284 where
285 C: SaTokenConfigurator;
286}
287
288impl SaTokenAuthConfigurator for AppBuilder {
289 #[allow(deprecated)]
290 fn sa_token_auth<C>(&mut self, configurator: C) -> &mut Self
291 where
292 C: SaTokenConfigurator,
293 {
294 self.sa_token_configure(configurator)
295 }
296
297 fn sa_token_configure<C>(&mut self, configurator: C) -> &mut Self
298 where
299 C: SaTokenConfigurator,
300 {
301 if let Some(storage) = configurator.configure_storage(self) {
302 self.add_component(crate::custom_storage::SaTokenStorage::new(storage));
303 }
304
305 let builder = configurator.configure_path_auth(PathAuthBuilder::new());
306 if builder.is_configured() {
307 let config = builder.build();
308 self.add_component(config)
309 } else {
310 self
311 }
312 }
313}
314
315impl SaTokenConfigurator for PathAuthBuilder {
316 fn configure_path_auth(&self, auth: PathAuthBuilder) -> PathAuthBuilder {
317 auth.merge(self.clone())
318 }
319}