0
# Servlet Filters and Integration
1
2
Comprehensive servlet filter system providing the foundation for Apache Shiro's web security functionality. These filters handle request processing, provide template patterns for security operations, and integrate seamlessly with servlet containers while maintaining Shiro's security context throughout the request lifecycle.
3
4
## Capabilities
5
6
### Primary Servlet Filters
7
8
Core servlet filters that serve as entry points for Shiro security processing in web applications.
9
10
```java { .api }
11
class ShiroFilter extends AbstractShiroFilter {
12
/**
13
* Creates a new ShiroFilter that uses ServletContext-configured WebEnvironment.
14
*/
15
public ShiroFilter();
16
17
/**
18
* Initializes the filter by retrieving the WebEnvironment from ServletContext.
19
* The WebEnvironment should be configured by EnvironmentLoaderListener.
20
*
21
* @throws ServletException if WebEnvironment is not found in ServletContext
22
*/
23
public void init() throws ServletException;
24
}
25
```
26
27
```java { .api }
28
class IniShiroFilter extends AbstractShiroFilter {
29
/** Default INI resource path */
30
public static final String DEFAULT_WEB_INI_RESOURCE_PATH = "/WEB-INF/shiro.ini";
31
32
/**
33
* Creates a new IniShiroFilter using default INI resource path.
34
*/
35
public IniShiroFilter();
36
37
/**
38
* Returns the configuration resource locations.
39
*
40
* @return array of configuration resource paths
41
*/
42
public String[] getConfigPath();
43
44
/**
45
* Sets the configuration resource locations.
46
*
47
* @param configPath array of configuration resource paths
48
*/
49
public void setConfigPath(String[] configPath);
50
51
/**
52
* Initializes the filter by loading configuration from INI resources.
53
*
54
* @throws ServletException if initialization fails
55
*/
56
public void init() throws ServletException;
57
}
58
```
59
60
### Abstract Filter Base Classes
61
62
Base classes providing template patterns and common functionality for Shiro servlet filters.
63
64
```java { .api }
65
abstract class AbstractShiroFilter extends OncePerRequestFilter {
66
/** ServletContext attribute key for storing WebEnvironment */
67
public static final String STATIC_INIT_PARAM_NAME = "staticSecurityManagerEnabled";
68
69
/**
70
* Returns the WebSecurityManager used by this filter.
71
*
72
* @return the WebSecurityManager instance
73
*/
74
public WebSecurityManager getSecurityManager();
75
76
/**
77
* Sets the WebSecurityManager for this filter.
78
*
79
* @param securityManager the WebSecurityManager to set
80
*/
81
public void setSecurityManager(WebSecurityManager securityManager);
82
83
/**
84
* Returns the FilterChainResolver used to resolve filter chains.
85
*
86
* @return the FilterChainResolver instance
87
*/
88
public FilterChainResolver getFilterChainResolver();
89
90
/**
91
* Sets the FilterChainResolver for this filter.
92
*
93
* @param filterChainResolver the FilterChainResolver to set
94
*/
95
public void setFilterChainResolver(FilterChainResolver filterChainResolver);
96
97
/**
98
* Returns whether static SecurityManager access is enabled.
99
*
100
* @return true if static SecurityManager is enabled
101
*/
102
public boolean isStaticSecurityManagerEnabled();
103
104
/**
105
* Sets whether static SecurityManager access is enabled.
106
*
107
* @param staticSecurityManagerEnabled true to enable static SecurityManager
108
*/
109
public void setStaticSecurityManagerEnabled(boolean staticSecurityManagerEnabled);
110
111
/**
112
* Sets the configuration for this filter.
113
*
114
* @param config the ShiroFilterConfiguration to set
115
*/
116
public void setShiroFilterConfiguration(ShiroFilterConfiguration config);
117
118
/**
119
* Template method for processing web requests with Shiro security.
120
*
121
* @param request the servlet request
122
* @param response the servlet response
123
* @param chain the filter chain
124
* @throws ServletException if servlet processing fails
125
* @throws IOException if I/O error occurs
126
*/
127
protected void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
128
throws ServletException, IOException;
129
130
/**
131
* Creates a Subject instance for the current request.
132
*
133
* @param request the servlet request
134
* @param response the servlet response
135
* @return the created Subject instance
136
*/
137
protected WebSubject createSubject(ServletRequest request, ServletResponse response);
138
139
/**
140
* Updates the session last access time if needed.
141
*
142
* @param request the servlet request
143
* @param response the servlet response
144
*/
145
protected void updateSessionLastAccessTime(ServletRequest request, ServletResponse response);
146
}
147
```
148
149
```java { .api }
150
abstract class OncePerRequestFilter extends NameableFilter {
151
/** Request attribute key to mark filter execution */
152
public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";
153
154
/**
155
* Ensures the filter executes only once per request.
156
*
157
* @param request the servlet request
158
* @param response the servlet response
159
* @param filterChain the filter chain
160
* @throws ServletException if servlet processing fails
161
* @throws IOException if I/O error occurs
162
*/
163
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
164
throws ServletException, IOException;
165
166
/**
167
* Template method for actual filter processing, called only once per request.
168
*
169
* @param request the servlet request
170
* @param response the servlet response
171
* @param chain the filter chain
172
* @throws ServletException if servlet processing fails
173
* @throws IOException if I/O error occurs
174
*/
175
protected abstract void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
176
throws ServletException, IOException;
177
178
/**
179
* Returns whether this filter should execute for the given request.
180
*
181
* @param request the servlet request
182
* @return true if filter should execute
183
*/
184
protected boolean isEnabled(ServletRequest request, ServletResponse response);
185
186
/**
187
* Returns the request attribute key used to mark filter execution.
188
*
189
* @return the attribute key string
190
*/
191
private String getAlreadyFilteredAttributeName();
192
}
193
```
194
195
```java { .api }
196
abstract class AdviceFilter extends OncePerRequestFilter {
197
/**
198
* Template method providing pre-processing, actual filtering, and post-processing.
199
*
200
* @param request the servlet request
201
* @param response the servlet response
202
* @param chain the filter chain
203
* @throws ServletException if servlet processing fails
204
* @throws IOException if I/O error occurs
205
*/
206
protected void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
207
throws ServletException, IOException;
208
209
/**
210
* Pre-processing hook executed before the filter chain continues.
211
*
212
* @param request the servlet request
213
* @param response the servlet response
214
* @return true to continue with the filter chain, false to stop processing
215
* @throws Exception if pre-processing fails
216
*/
217
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception;
218
219
/**
220
* Post-processing hook executed after the filter chain completes successfully.
221
*
222
* @param request the servlet request
223
* @param response the servlet response
224
* @throws Exception if post-processing fails
225
*/
226
protected void postHandle(ServletRequest request, ServletResponse response) throws Exception;
227
228
/**
229
* Cleanup hook executed after request processing, regardless of success or failure.
230
*
231
* @param request the servlet request
232
* @param response the servlet response
233
* @param exception any exception that occurred during processing, or null
234
* @throws Exception if cleanup fails
235
*/
236
protected void afterCompletion(ServletRequest request, ServletResponse response, Exception exception)
237
throws Exception;
238
239
/**
240
* Executes the filter chain.
241
*
242
* @param request the servlet request
243
* @param response the servlet response
244
* @param chain the filter chain
245
* @throws Exception if chain execution fails
246
*/
247
protected void executeChain(ServletRequest request, ServletResponse response, FilterChain chain)
248
throws Exception;
249
}
250
```
251
252
### Base Filter Classes
253
254
Foundation classes providing common servlet filter functionality and naming capabilities.
255
256
```java { .api }
257
abstract class NameableFilter extends AbstractFilter {
258
/**
259
* Returns the name of this filter.
260
*
261
* @return the filter name
262
*/
263
public String getName();
264
265
/**
266
* Sets the name of this filter.
267
*
268
* @param name the filter name to set
269
*/
270
public void setName(String name);
271
272
/**
273
* Returns a string representation including the filter name.
274
*
275
* @return string representation of this filter
276
*/
277
public String toString();
278
}
279
```
280
281
```java { .api }
282
abstract class AbstractFilter implements Filter {
283
/**
284
* Default implementation that does nothing.
285
*
286
* @param filterConfig the filter configuration
287
* @throws ServletException if initialization fails
288
*/
289
public void init(FilterConfig filterConfig) throws ServletException;
290
291
/**
292
* Default implementation that does nothing.
293
*/
294
public void destroy();
295
296
/**
297
* Returns a string representation of this filter.
298
*
299
* @return string representation
300
*/
301
public String toString();
302
}
303
```
304
305
### Path-Based Filtering
306
307
Filters that can be configured to apply different behavior based on request paths using Ant-style path patterns.
308
309
```java { .api }
310
abstract class PathMatchingFilter extends AdviceFilter implements PathConfigProcessor {
311
/** Log instance for this class */
312
private static final Logger log = LoggerFactory.getLogger(PathMatchingFilter.class);
313
314
/**
315
* Returns the path patterns and their associated configuration.
316
*
317
* @return Map of path patterns to configuration
318
*/
319
protected Map<String, Object> getPathConfigMap();
320
321
/**
322
* Sets the path patterns and their associated configuration.
323
*
324
* @param pathConfigMap Map of path patterns to configuration
325
*/
326
protected void setPathConfigMap(Map<String, Object> pathConfigMap);
327
328
/**
329
* Returns the path-specific configuration for the current request.
330
*
331
* @param request the servlet request
332
* @param response the servlet response
333
* @return the configuration object for the matching path
334
*/
335
protected Object getPathConfig(ServletRequest request, ServletResponse response);
336
337
/**
338
* Determines if the request path matches any configured patterns.
339
*
340
* @param path the request path
341
* @param request the servlet request
342
* @return true if path matches a configured pattern
343
*/
344
protected boolean pathsMatch(String path, ServletRequest request);
345
346
/**
347
* Returns the request path for pattern matching.
348
*
349
* @param request the servlet request
350
* @return the request path
351
*/
352
protected String getPathWithinApplication(ServletRequest request);
353
354
/**
355
* Pre-processing that applies path-specific configuration.
356
*
357
* @param request the servlet request
358
* @param response the servlet response
359
* @return true to continue processing
360
* @throws Exception if pre-processing fails
361
*/
362
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception;
363
364
/**
365
* Template method called when a request matches a configured path pattern.
366
*
367
* @param request the servlet request
368
* @param response the servlet response
369
* @param mappedValue the configuration associated with the matched path
370
* @return true to continue processing
371
* @throws Exception if processing fails
372
*/
373
protected abstract boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
374
throws Exception;
375
376
/**
377
* Processes path-specific configuration strings.
378
*
379
* @param path the path pattern
380
* @param config the configuration string
381
* @return the processed configuration object
382
*/
383
public Object processPathConfig(String path, String config);
384
}
385
```
386
387
### Access Control Filters
388
389
Base class for filters that control access to resources, providing login URL management and request saving/restoration functionality.
390
391
```java { .api }
392
abstract class AccessControlFilter extends PathMatchingFilter {
393
/** Default login URL */
394
public static final String DEFAULT_LOGIN_URL = "/login";
395
396
/** Request parameter name for original request URL */
397
public static final String DEFAULT_SUCCESS_URL_PARAM = "successUrl";
398
399
/**
400
* Returns the login URL.
401
*
402
* @return the login URL
403
*/
404
public String getLoginUrl();
405
406
/**
407
* Sets the login URL.
408
*
409
* @param loginUrl the login URL to set
410
*/
411
public void setLoginUrl(String loginUrl);
412
413
/**
414
* Handles request processing by checking access permissions.
415
*
416
* @param request the servlet request
417
* @param response the servlet response
418
* @param mappedValue the configuration for this path
419
* @return true to continue processing
420
* @throws Exception if processing fails
421
*/
422
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
423
throws Exception;
424
425
/**
426
* Determines if access is allowed for the current request.
427
*
428
* @param request the servlet request
429
* @param response the servlet response
430
* @param mappedValue the configuration for this path
431
* @return true if access is allowed
432
* @throws Exception if access check fails
433
*/
434
protected abstract boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
435
throws Exception;
436
437
/**
438
* Handles the case when access is denied.
439
*
440
* @param request the servlet request
441
* @param response the servlet response
442
* @return true if the denial was handled and processing should continue
443
* @throws Exception if handling access denial fails
444
*/
445
protected abstract boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception;
446
447
/**
448
* Saves the current request and redirects to the login URL.
449
*
450
* @param request the servlet request
451
* @param response the servlet response
452
* @throws IOException if redirect fails
453
*/
454
protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response)
455
throws IOException;
456
457
/**
458
* Saves the current request for later restoration.
459
*
460
* @param request the servlet request
461
*/
462
protected void saveRequest(ServletRequest request);
463
464
/**
465
* Redirects to the login URL.
466
*
467
* @param request the servlet request
468
* @param response the servlet response
469
* @throws IOException if redirect fails
470
*/
471
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException;
472
473
/**
474
* Returns the URL to redirect to after successful login.
475
*
476
* @param request the servlet request
477
* @param response the servlet response
478
* @param mappedValue the configuration for this path
479
* @return the success URL
480
*/
481
protected String getSuccessUrl(ServletRequest request, ServletResponse response, Object mappedValue);
482
}
483
```
484
485
### Request Security Filter
486
487
Filter for blocking potentially malicious requests based on various security criteria.
488
489
```java { .api }
490
class InvalidRequestFilter extends AccessControlFilter {
491
/**
492
* Creates a new InvalidRequestFilter with default settings.
493
*/
494
public InvalidRequestFilter();
495
496
/**
497
* Determines if the request is valid and access should be allowed.
498
*
499
* @param request the servlet request
500
* @param response the servlet response
501
* @param mappedValue the configuration for this path
502
* @return false if request appears invalid
503
* @throws Exception if validation fails
504
*/
505
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
506
throws Exception;
507
508
/**
509
* Handles invalid requests by sending an error response.
510
*
511
* @param request the servlet request
512
* @param response the servlet response
513
* @return false to stop further processing
514
* @throws Exception if error handling fails
515
*/
516
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception;
517
518
/**
519
* Checks if the request contains potentially malicious content.
520
*
521
* @param request the servlet request
522
* @return true if request appears malicious
523
*/
524
private boolean containsSemicolon(ServletRequest request);
525
526
/**
527
* Checks if the request contains backslash characters.
528
*
529
* @param request the servlet request
530
* @return true if request contains backslashes
531
*/
532
private boolean containsBackslash(ServletRequest request);
533
534
/**
535
* Checks if the request contains non-ASCII characters.
536
*
537
* @param request the servlet request
538
* @return true if request contains non-ASCII characters
539
*/
540
private boolean containsNonAsciiCharacters(ServletRequest request);
541
}
542
```
543
544
## Usage Examples
545
546
### Basic Filter Configuration
547
548
```java
549
// web.xml configuration
550
/*
551
<filter>
552
<filter-name>ShiroFilter</filter-name>
553
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
554
</filter>
555
556
<filter-mapping>
557
<filter-name>ShiroFilter</filter-name>
558
<url-pattern>/*</url-pattern>
559
<dispatcher>REQUEST</dispatcher>
560
<dispatcher>FORWARD</dispatcher>
561
<dispatcher>INCLUDE</dispatcher>
562
<dispatcher>ERROR</dispatcher>
563
</filter-mapping>
564
*/
565
566
// Programmatic filter setup
567
public void configureFilter(ServletContext servletContext) {
568
ShiroFilter shiroFilter = new ShiroFilter();
569
570
FilterRegistration.Dynamic registration = servletContext.addFilter("ShiroFilter", shiroFilter);
571
registration.setInitParameter("staticSecurityManagerEnabled", "false");
572
registration.addMappingForUrlPatterns(
573
EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ERROR),
574
false, "/*");
575
}
576
```
577
578
### Custom Filter Implementation
579
580
```java
581
public class CustomSecurityFilter extends AccessControlFilter {
582
private String customLoginUrl = "/custom-login";
583
584
@Override
585
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
586
throws Exception {
587
Subject subject = getSubject(request, response);
588
589
// Custom access logic
590
return subject.isAuthenticated() && subject.hasRole("custom-role");
591
}
592
593
@Override
594
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
595
if (isLoginRequest(request, response)) {
596
return true; // Allow login requests through
597
} else {
598
saveRequestAndRedirectToLogin(request, response);
599
return false;
600
}
601
}
602
603
private boolean isLoginRequest(ServletRequest request, ServletResponse response) {
604
return pathsMatch(customLoginUrl, request);
605
}
606
607
@Override
608
public String getLoginUrl() {
609
return customLoginUrl;
610
}
611
}
612
```
613
614
### Filter Chain Configuration
615
616
```java
617
public class FilterChainConfig {
618
public void setupFilterChains() {
619
DefaultFilterChainManager manager = new DefaultFilterChainManager();
620
621
// Add custom filters
622
manager.addFilter("custom", new CustomSecurityFilter());
623
manager.addFilter("invalidRequest", new InvalidRequestFilter());
624
625
// Create filter chains
626
manager.createChain("/api/**", "invalidRequest, authc, perms[api:read]");
627
manager.createChain("/admin/**", "authc, roles[admin]");
628
manager.createChain("/custom/**", "custom");
629
manager.createChain("/**", "anon");
630
631
// Use with PathMatchingFilterChainResolver
632
PathMatchingFilterChainResolver resolver = new PathMatchingFilterChainResolver();
633
resolver.setFilterChainManager(manager);
634
}
635
}
636
```