Spring Security Web module provides comprehensive security services and servlet integration for web applications built with the Spring Framework
The filter chain infrastructure is the foundation of Spring Security Web, managing the security filter chain that processes HTTP requests.
Required Dependencies:
spring-security-web (this package)spring-security-core is required (provides SecurityContextHolderStrategy, AuthenticationException)spring-security-config is required for HttpSecurity DSL and SecurityFilterChain bean creationFilter interfaceGenericFilterBean and OncePerRequestFilterDefault Behaviors:
StrictHttpFirewall (rejects suspicious requests)DefaultRequestRejectedHandler (rethrows exception)SecurityFilterChain is used (order matters)ObservationFilterChainDecorator for metrics)DefaultRedirectStrategy with HTTP 302 statusPortMapperImpl with default mappings (80:443, 8080:8443)LoginUrlAuthenticationEntryPoint (redirects to /login)Threading Model:
FilterChainProxy.doFilter() executes on servlet container thread (synchronous)SecurityFilterChain.matches() called for each chain until match foundLifecycle:
FilterChainProxy implements Filter (registered in servlet container via FilterRegistrationBean)SecurityFilterChain beans are discovered and collected at application startupFilterChainProxy.afterPropertiesSet() validates filter chain configurationExceptions:
RequestRejectedException - Firewall rejects request (wrapped by request rejected handler)UnreachableFilterChainException - Filter chain configuration error (chain cannot be reached)ServletException, IOException - Standard servlet exceptions from filter processingIllegalArgumentException - Invalid filter chain configurationEdge Cases:
SecurityFilterChain beans: Order matters, first matching chain is usedforceHttps=true in LoginUrlAuthenticationEntryPointsetContextRelative(true)RequestRejectedException or application will fail/api/** before /**)FilterChainProxy is the central entry point that delegates Filter requests to Spring-managed security filter chains.
package org.springframework.security.web;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
import java.util.List;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.RequestRejectedHandler;
import org.springframework.web.filter.GenericFilterBean;
public class FilterChainProxy extends GenericFilterBean {
/**
* Creates an empty FilterChainProxy with no filter chains.
*/
public FilterChainProxy();
/**
* Creates a FilterChainProxy with a single security filter chain.
*
* @param chain the SecurityFilterChain instance
*/
public FilterChainProxy(SecurityFilterChain chain);
/**
* Creates a FilterChainProxy with the given security filter chains.
*
* @param filterChains the list of SecurityFilterChain instances
*/
public FilterChainProxy(List<SecurityFilterChain> filterChains);
/**
* Delegates the request through the matching security filter chain.
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
/**
* Sets the HttpFirewall for request validation.
* Default is StrictHttpFirewall.
*/
public void setFirewall(HttpFirewall firewall);
/**
* Sets the handler for rejected requests.
*/
public void setRequestRejectedHandler(RequestRejectedHandler requestRejectedHandler);
/**
* Sets the SecurityContextHolderStrategy.
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy);
/**
* Sets a validator for the filter chain configuration.
*/
public void setFilterChainValidator(FilterChainValidator filterChainValidator);
/**
* Sets a decorator for customizing the filter chain execution.
*/
public void setFilterChainDecorator(FilterChainDecorator filterChainDecorator);
/**
* Returns the list of SecurityFilterChains which will be matched against
* and applied to incoming requests.
*
* @return unmodifiable list of SecurityFilterChain instances
*/
public List<SecurityFilterChain> getFilterChains();
/**
* Convenience method for getting filters for a specific URL, mainly for testing.
*
* @param url the URL to match
* @return list of Filter instances or null if no chain matches
*/
public List<Filter> getFilters(String url);
public void afterPropertiesSet();
public String toString();
}SecurityFilterChain defines a filter chain capable of matching requests and providing filters.
package org.springframework.security.web;
import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
public interface SecurityFilterChain {
/**
* Determines if this filter chain applies to the given request.
*
* @param request the HttpServletRequest to match
* @return true if this filter chain should process the request
*/
boolean matches(HttpServletRequest request);
/**
* Returns the list of filters to be applied.
*
* @return the ordered list of Filter instances
*/
List<Filter> getFilters();
}Standard implementation of SecurityFilterChain (Since 3.1).
package org.springframework.security.web;
import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.web.util.matcher.RequestMatcher;
import java.util.List;
/**
* Standard implementation of SecurityFilterChain.
*/
public final class DefaultSecurityFilterChain implements SecurityFilterChain {
/**
* Creates a DefaultSecurityFilterChain with a RequestMatcher and filters.
*
* @param requestMatcher the matcher to determine if this chain applies
* @param filters the filters to be applied (varargs)
*/
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters);
/**
* Creates a DefaultSecurityFilterChain with a RequestMatcher and a list of filters.
*
* @param requestMatcher the matcher to determine if this chain applies
* @param filters the list of filters to be applied
*/
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters);
/**
* Returns the RequestMatcher used by this filter chain.
*
* @return the RequestMatcher instance
*/
public RequestMatcher getRequestMatcher();
/**
* Returns the list of filters in this chain.
*
* @return the ordered list of Filter instances
*/
public List<Filter> getFilters();
/**
* Determines if this filter chain applies to the given request.
*
* @param request the HttpServletRequest to match
* @return true if this filter chain should process the request
*/
public boolean matches(HttpServletRequest request);
}FilterInvocation holds HTTP filter-related objects and provides request information.
package org.springframework.security.web;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class FilterInvocation {
/**
* Creates a FilterInvocation from actual servlet objects.
*
* @param request the ServletRequest
* @param response the ServletResponse
* @param chain the FilterChain
*/
public FilterInvocation(ServletRequest request, ServletResponse response, FilterChain chain);
public FilterChain getChain();
public String getFullRequestUrl();
public HttpServletRequest getHttpRequest();
public HttpServletResponse getHttpResponse();
public String getRequestUrl();
public HttpServletRequest getRequest();
public HttpServletResponse getResponse();
public String getCharacterEncoding();
public String getContextPath();
public String toString();
}Utility filter that redirects requests matching a RequestMatcher to a specified URL (Since 5.6).
package org.springframework.security.web;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
/**
* Filter that redirects requests that match RequestMatcher to the specified URL.
*/
public final class RequestMatcherRedirectFilter extends OncePerRequestFilter {
/**
* Creates a RequestMatcherRedirectFilter.
*
* @param requestMatcher the request matcher to determine which requests to redirect
* @param redirectUrl the URL to redirect to
*/
public RequestMatcherRedirectFilter(RequestMatcher requestMatcher, String redirectUrl);
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException;
}AuthenticationEntryPoint commences an authentication scheme when authentication is required.
package org.springframework.security.web;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.security.core.AuthenticationException;
public interface AuthenticationEntryPoint {
/**
* Commences an authentication scheme.
* Called by ExceptionTranslationFilter when authentication is required.
*
* @param request the request during which authentication failed
* @param response the response
* @param authException the exception that caused authentication to fail
*/
void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException;
}Redirects to a login page when authentication is required.
package org.springframework.security.web.authentication;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.RedirectStrategy;
public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoint {
/**
* Creates an entry point with the specified login form URL.
*
* @param loginFormUrl the URL of the login page
*/
public LoginUrlAuthenticationEntryPoint(String loginFormUrl);
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException;
/**
* Forces HTTPS for the login page.
*/
public void setForceHttps(boolean forceHttps);
/**
* Sets the PortMapper for HTTP to HTTPS redirection.
*/
public void setPortMapper(PortMapper portMapper);
/**
* Uses forward instead of redirect to login page.
*/
public void setUseForward(boolean useForward);
/**
* Enables relative URIs in redirects.
*/
public void setFavorRelativeUris(boolean favorRelativeUris);
public String getLoginFormUrl();
public int getServerPort(ServletRequest request);
public void afterPropertiesSet();
}Returns HTTP 403 Forbidden for pre-authenticated scenarios.
package org.springframework.security.web.authentication;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
public class Http403ForbiddenEntryPoint implements AuthenticationEntryPoint {
public Http403ForbiddenEntryPoint();
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException arg2) throws IOException, ServletException;
}Selects an AuthenticationEntryPoint based on RequestMatcher evaluation.
package org.springframework.security.web.authentication;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.LinkedHashMap;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.RequestMatcher;
public class DelegatingAuthenticationEntryPoint implements AuthenticationEntryPoint {
/**
* Creates a delegating entry point with RequestMatcher to EntryPoint mappings.
*
* @param entryPoints map of RequestMatcher to AuthenticationEntryPoint
*/
public DelegatingAuthenticationEntryPoint(
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints);
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException;
/**
* Sets the default entry point when no matcher matches.
*/
public void setDefaultEntryPoint(AuthenticationEntryPoint defaultEntryPoint);
public void afterPropertiesSet();
/**
* Creates a builder for configuring entry points.
*/
public static Builder builder();
}package org.springframework.security.web.authentication;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.RequestMatcher;
public static final class DelegatingAuthenticationEntryPoint.Builder {
/**
* Sets the default entry point.
*/
public Builder defaultEntryPoint(AuthenticationEntryPoint defaultEntryPoint);
/**
* Adds an entry point for the given request matcher.
*/
public Builder addEntryPointFor(AuthenticationEntryPoint entryPoint, RequestMatcher requestMatcher);
/**
* Builds the DelegatingAuthenticationEntryPoint.
*/
public AuthenticationEntryPoint build();
}An AuthenticationEntryPoint that does nothing.
package org.springframework.security.web.authentication;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
public class NoOpAuthenticationEntryPoint implements AuthenticationEntryPoint {
public NoOpAuthenticationEntryPoint();
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException;
}Interface for decorating filter chain execution.
package org.springframework.security.web;
import jakarta.servlet.FilterChain;
public interface FilterChainDecorator {
/**
* Decorates the filter chain with additional behavior.
*
* @param filterChain the original filter chain
* @return the decorated filter chain
*/
FilterChain decorate(FilterChain filterChain);
}Decorates filter chain with observability support using Micrometer.
package org.springframework.security.web;
import io.micrometer.observation.ObservationRegistry;
import jakarta.servlet.FilterChain;
public class ObservationFilterChainDecorator implements FilterChainDecorator {
/**
* Creates a decorator with the given observation registry.
*
* @param observationRegistry the Micrometer observation registry
*/
public ObservationFilterChainDecorator(ObservationRegistry observationRegistry);
public FilterChain decorate(FilterChain filterChain);
}Constants for storing security-related attributes in request/session scope.
package org.springframework.security.web;
public final class WebAttributes {
/**
* Attribute for storing authentication exception.
*/
public static final String AUTHENTICATION_EXCEPTION =
"SPRING_SECURITY_LAST_EXCEPTION";
/**
* Attribute for storing access denied exception.
*/
public static final String ACCESS_DENIED_403 =
"SPRING_SECURITY_403_EXCEPTION";
/**
* Attribute for storing web invocation privilege evaluator.
*/
public static final String WEB_INVOCATION_PRIVILEGE_EVALUATOR_ATTRIBUTE =
"org.springframework.security.web.access.WebInvocationPrivilegeEvaluator.CONTEXT_ATTRIBUTE";
}Interface for redirection logic.
package org.springframework.security.web;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public interface RedirectStrategy {
/**
* Performs a redirect to the supplied URL.
*
* @param request the current request
* @param response the response to redirect
* @param url the target URL
*/
void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
throws IOException;
}Default implementation of RedirectStrategy.
package org.springframework.security.web;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.http.HttpStatus;
public class DefaultRedirectStrategy implements RedirectStrategy {
public DefaultRedirectStrategy();
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
throws IOException;
/**
* Makes the redirect URL relative to the context path.
*/
public void setContextRelative(boolean useRelativeContext);
/**
* Sets the HTTP status code for redirects (default: 302).
*/
public void setStatusCode(HttpStatus statusCode);
}Maps HTTP ports to HTTPS ports for secure redirects.
package org.springframework.security.web;
import jakarta.servlet.ServletRequest;
public interface PortMapper {
/**
* Locates the HTTP port for the given HTTPS port.
*
* @param httpsPort the HTTPS port
* @return the corresponding HTTP port, or null if unknown
*/
Integer lookupHttpPort(Integer httpsPort);
/**
* Locates the HTTPS port for the given HTTP port.
*
* @param httpPort the HTTP port
* @return the corresponding HTTPS port, or null if unknown
*/
Integer lookupHttpsPort(Integer httpPort);
}Default PortMapper implementation with configurable mappings.
package org.springframework.security.web;
import java.util.Map;
public class PortMapperImpl implements PortMapper {
public PortMapperImpl();
public Integer lookupHttpPort(Integer httpsPort);
public Integer lookupHttpsPort(Integer httpPort);
/**
* Sets custom port mappings. Keys are String HTTP ports, values are String HTTPS ports.
* Default mappings are 80:443 and 8080:8443.
*
* @param newMappings map of HTTP to HTTPS port mappings
*/
public void setPortMappings(Map<String, String> newMappings);
}Thrown when a SecurityFilterChain cannot be reached due to configuration issues.
package org.springframework.security.web;
public class UnreachableFilterChainException extends IllegalArgumentException {
/**
* Creates an exception with the specified message.
*
* @param message the detail message
*/
public UnreachableFilterChainException(String message);
/**
* Creates an exception with filter chain details.
*
* @param message the detail message
* @param filterChain the filter chain that caused the issue
* @param unreachableFilterChain the unreachable filter chain
*/
public UnreachableFilterChainException(String message, SecurityFilterChain filterChain,
SecurityFilterChain unreachableFilterChain);
public SecurityFilterChain getFilterChain();
public SecurityFilterChain getUnreachableFilterChain();
}import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http
.securityMatchers(matchers -> matchers
.requestMatchers("/api/**")
)
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults());
return http.build();
}
@Bean
public SecurityFilterChain webFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
);
return http.build();
}
}import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\": \"Authentication required\"}");
}
}
// Configure in security chain
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.exceptionHandling(handling -> handling
.authenticationEntryPoint(new CustomAuthenticationEntryPoint())
);
return http.build();
}import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
@Bean
public AuthenticationEntryPoint delegatingEntryPoint() {
return DelegatingAuthenticationEntryPoint.builder()
.addEntryPointFor(
new Http403ForbiddenEntryPoint(),
PathPatternRequestMatcher.pathPattern("/api/**")
)
.addEntryPointFor(
new LoginUrlAuthenticationEntryPoint("/login"),
PathPatternRequestMatcher.pathPattern("/admin/**")
)
.defaultEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.build();
}import org.springframework.security.web.FilterChainDecorator;
import org.springframework.security.web.ObservationFilterChainDecorator;
import io.micrometer.observation.ObservationRegistry;
import jakarta.servlet.FilterChain;
@Configuration
public class ObservableSecurityConfig {
@Bean
public FilterChainProxy filterChainProxy(List<SecurityFilterChain> filterChains,
ObservationRegistry observationRegistry) {
FilterChainProxy proxy = new FilterChainProxy(filterChains);
// Add observability support
proxy.setFilterChainDecorator(
new ObservationFilterChainDecorator(observationRegistry)
);
return proxy;
}
}import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
@Configuration
public class MultiChainConfig {
// High priority: API endpoints
@Bean
@Order(1)
public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
http
.securityMatchers(matchers -> matchers
.requestMatchers(PathPatternRequestMatcher.pathPattern("/api/**"))
)
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.httpBasic(basic -> {})
.csrf(csrf -> csrf.disable());
return http.build();
}
// Lower priority: Web endpoints
@Bean
@Order(2)
public SecurityFilterChain webChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
);
return http.build();
}
}import org.springframework.security.web.firewall.RequestRejectedException;
import org.springframework.security.web.firewall.RequestRejectedHandler;
public class LoggingRequestRejectedHandler implements RequestRejectedHandler {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
RequestRejectedException requestRejectedException)
throws IOException, ServletException {
logger.warn("Request rejected: {} {} from {} - {}",
request.getMethod(),
request.getRequestURI(),
request.getRemoteAddr(),
requestRejectedException.getMessage()
);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setContentType("application/json");
response.getWriter().write(
"{\"error\": \"Invalid request\", \"message\": \"" +
requestRejectedException.getMessage() + "\"}"
);
}
}
// Configuration
@Bean
public FilterChainProxy filterChainProxy(List<SecurityFilterChain> filterChains) {
FilterChainProxy proxy = new FilterChainProxy(filterChains);
proxy.setRequestRejectedHandler(new LoggingRequestRejectedHandler());
return proxy;
}Install with Tessl CLI
npx tessl i tessl/maven-spring-security-web