Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the core filter chain of Spring Security

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "what is the core filter chain of Spring Security". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Now let the editor take you to learn "what is the core filter chain of Spring Security"?

1. Filter Chain diagram

After spring security is configured, when the project is run, DefaultSecurityFilterChain will output the relevant log:

Public DefaultSecurityFilterChain (RequestMatcher requestMatcher, List filters) {logger.info ("Creating filter chain:" + requestMatcher + "," + filters); this.requestMatcher = requestMatcher; this.filters = new ArrayList (filters);}

Output the following Log:

[main] o.s.s.web.DefaultSecurityFilterChain:

Creating filter chain:

Org.springframework.security.web.util.matcher.AnyRequestMatcher@1

[

Org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@184de357

Org.springframework.security.web.context.SecurityContextPersistenceFilter@521ba38f

Org.springframework.security.web.header.HeaderWriterFilter@77bb916f

Org.springframework.security.web.csrf.CsrfFilter@76b305e1

Org.springframework.security.web.authentication.logout.LogoutFilter@17c53dfb

Org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2086d469

Org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@b1d19ff

Org.springframework.security.web.authentication.AnonymousAuthenticationFilter@efe49ab

Org.springframework.security.web.session.SessionManagementFilter@5a48d186

Org.springframework.security.web.access.ExceptionTranslationFilter@273aaab7

]

You can also view it from Debug:

2. Analysis of filters one by one

Before parsing, let's talk about two vital classes: OncePerRequestFilter and GenericFilterBean, which inherit more or less indirectly or directly from the filter in the filter chain.

As the name implies, OncePerRequestFilter ensures that only one filter is passed at a time, without the need for repeated execution.

GenericFilterBean is a basic implementation class of the javax.servlet.Filter interface

GenericFilterBean takes the configuration parameter-init-param entry in the filter tag of web.xml as the attribute of bean

GenericFilterBean can simply be the parent class of any type of filter

Subclasses of GenericFilterBean can customize some of the properties they need.

GenericFilterBean, leaving the actual filtering work to his subclass, which causes his subclass to have to implement the doFilter method

ApplicationContext,Filters that GenericFilterBean does not depend on Spring usually does not read their container information (ApplicationContext concept) directly, but obtains it by accessing service beans in the spring container (Spring root application context), usually by calling the getServletContext () method in filter.

2.1.WebAsyncManagerIntegrationFilter public final class WebAsyncManagerIntegrationFilter extends OncePerRequestFilter {. @ Override protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager (request); SecurityContextCallableProcessingInterceptor securityProcessingInterceptor = (SecurityContextCallableProcessingInterceptor) asyncManager .getCallableInterceptor (CALLABLE_INTERCEPTOR_KEY); if (securityProcessingInterceptor = = null) {asyncManager.registerCallableInterceptor (CALLABLE_INTERCEPTOR_KEY, new SecurityContextCallableProcessingInterceptor ());} filterChain.doFilter (request, response);}}

From the source code, we can analyze the related functions of WebAsyncManagerIntegrationFilter:

Obtain WebAsyncManager based on request encapsulation

Get / register SecurityContextCallableProcessingInterceptor from WebAsyncManager

2.2.SecurityContextPersistenceFilterpublic class SecurityContextPersistenceFilter extends GenericFilterBean {. Public void doFilter (ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (request.getAttribute (FILTER_APPLIED)! = null) {/ / ensure that filter is only applied once per request chain.doFilter (request, response); return } final boolean debug = logger.isDebugEnabled (); request.setAttribute (FILTER_APPLIED, Boolean.TRUE); if (forceEagerSessionCreation) {HttpSession session = request.getSession (); if (debug & & session.isNew ()) {logger.debug ("Eagerly created session:" + session.getId ()) }} HttpRequestResponseHolder holder = new HttpRequestResponseHolder (request, response); SecurityContext contextBeforeChainExecution = repo.loadContext (holder); try {SecurityContextHolder.setContext (contextBeforeChainExecution); chain.doFilter (holder.getRequest (), holder.getResponse ()) } finally {SecurityContext contextAfterChainExecution = SecurityContextHolder .getContext (); / / Crucial removal of SecurityContextHolder contents-do this before anything / / else. SecurityContextHolder.clearContext (); repo.saveContext (contextAfterChainExecution, holder.getRequest (), holder.getResponse ()); request.removeAttribute (FILTER_APPLIED); if (debug) {logger.debug ("SecurityContextHolder now cleared, as request processing completed") }. }

From the source code, we can analyze the related functions of SecurityContextPersistenceFilter:

First instance SecurityContextHolder- > HttpSessionSecurityContextRepository (replaced by repo below). Function: it will extract the information of authenticated users from Session, improve efficiency and avoid querying user authentication information every time.

Build HttpRequestResponseHolder based on request and response

Repo acquires SecurityContext according to HttpRequestResponseHolder loading context

SecurityContextHolder sets the acquired SecurityContext to Context, and then continues to execute other filters down

Finally- > SecurityContextHolder gets the SecurityContext, clears it, and saves it and the request information to repo, removing the FILTER_APPLIED attribute from the request

2.3.HeaderWriterFilterpublic class HeaderWriterFilter extends OncePerRequestFilter {. Override protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {for (HeaderWriter headerWriter: headerWriters) {headerWriter.writeHeaders (request, response);} filterChain.doFilter (request, response);}}

From the source code, we can analyze the related functions of HeaderWriterFilter:

Add the appropriate information to the Header of the request, and use security:headers inside the http tag to control

2.4.CsrfFilterpublic final class CsrfFilter extends OncePerRequestFilter {. @ Override protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {request.setAttribute (HttpServletResponse.class.getName (), response); CsrfToken csrfToken = this.tokenRepository.loadToken (request); final boolean missingToken = csrfToken = = null; if (missingToken) {csrfToken = this.tokenRepository.generateToken (request); this.tokenRepository.saveToken (csrfToken, request, response) } request.setAttribute (CsrfToken.class.getName (), csrfToken); request.setAttribute (csrfToken.getParameterName (), csrfToken); if (! this.requireCsrfProtectionMatcher.matches (request)) {filterChain.doFilter (request, response); return;} String actualToken = request.getHeader (csrfToken.getHeaderName ()) If (actualToken = = null) {actualToken = request.getParameter (csrfToken.getParameterName ());} if (! csrfToken.getToken (). Equals (actualToken)) {if (this.logger.isDebugEnabled ()) {this.logger.debug ("Invalid CSRF token found for" + UrlUtils.buildFullRequestUrl (request)) } if (missingToken) {this.accessDeniedHandler.handle (request, response, new MissingCsrfTokenException (actualToken));} else {this.accessDeniedHandler.handle (request, response, new InvalidCsrfTokenException (csrfToken, actualToken));} return FilterChain.doFilter (request, response);}.}

From the source code, we can analyze the related functions of CsrfFilter:

Csrf is also known as cross-domain request forgery, in which the attacker visits a trusted site by falsifying a user request.

Verify that the token information of csrf is included for the request that needs to be verified, and if not, an error is reported. In this way, the attacking website cannot get the token information, and the information submitted across domains cannot be verified by the filter.

2.5.LogoutFilterpublic class LogoutFilter extends GenericFilterBean {. Public void doFilter (ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (requiresLogout (request, response)) {Authentication auth = SecurityContextHolder.getContext () .getAuthentication If (logger.isDebugEnabled ()) {logger.debug ("Logging out user'" + auth + "'and transferring to logout destination");} this.handler.logout (request, response, auth); logoutSuccessHandler.onLogoutSuccess (request, response, auth); return;} chain.doFilter (request, response) }.}

From the source code, we can analyze the related functions of LogoutFilter:

Match URL. Default is / logout.

After the match is successful, the user exits and clears the authentication information.

2.6.RequestCacheAwareFilterpublic class RequestCacheAwareFilter extends GenericFilterBean {. Public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest wrappedSavedRequest = requestCache.getMatchingRequest ((HttpServletRequest) request, (HttpServletResponse) response); chain.doFilter (wrappedSavedRequest = = null? Request: wrappedSavedRequest, response);}}

From the source code, we can analyze the related functions of RequestCacheAwareFilter:

A RequestCache is maintained internally through HttpSessionRequestCache for caching HttpServletRequest

2.7.SecurityContextHolderAwareRequestFilterpublic class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {. Public void doFilter (ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {chain.doFilter (this.requestFactory.create (HttpServletRequest) req, (HttpServletResponse) res), res);}.}

From the source code, we can analyze the related functions of SecurityContextHolderAwareRequestFilter:

ServletRequest is packaged once, which makes request have richer API.

2.8.AnonymousAuthenticationFilterpublic class AnonymousAuthenticationFilter extends GenericFilterBean implements InitializingBean {. Public void doFilter (ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {if (SecurityContextHolder.getContext (). GetAuthentication () = = null) {SecurityContextHolder.getContext () .setAuthentication (createAuthentication ((HttpServletRequest) req)) If (logger.isDebugEnabled ()) {logger.debug ("Populated SecurityContextHolder with anonymous token:'" + SecurityContextHolder.getContext () .getAuthentication () + "") }} else {if (logger.isDebugEnabled ()) {logger.debug ("SecurityContextHolder not populated with anonymous token, as it already contained:'" + SecurityContextHolder.getContext (). GetAuthentication () + "") }} chain.doFilter (req, res);

From the source code, we can analyze the related functions of AnonymousAuthenticationFilter:

When the authentication information in SecurityContextHolder is empty, an anonymous user is created and stored in SecurityContextHolder. Anonymous identity filter, which I personally think is very important, needs to be compared with UsernamePasswordAuthenticationFilter. In order to be compatible with unlogged-in access, spring security has also gone through a set of authentication process, which is just an anonymous identity.

Anonymous authentication filter, some people may think: anonymity and identity? The personal understanding of Anonymous anonymous identity is that Spirng Security gives an anonymous identity even to unauthenticated users for the sake of the unity of the overall logic. The location of the AnonymousAuthenticationFilter filter is also very scientific, it is located after the commonly used identity authentication filters (such as UsernamePasswordAuthenticationFilter, BasicAuthenticationFilter, RememberMeAuthenticationFilter), which means that only after the implementation of the above identity filter, SecurityContext still has no user information, AnonymousAuthenticationFilter this filter will be meaningful-based on the user's anonymous identity.

2.9.SessionManagementFilterpublic class SessionManagementFilter extends GenericFilterBean {. Public void doFilter (ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (request.getAttribute (FILTER_APPLIED)! = null) {chain.doFilter (request, response); return;} request.setAttribute (FILTER_APPLIED, Boolean.TRUE) If (! securityContextRepository.containsContext (request)) {Authentication authentication = SecurityContextHolder.getContext () .getAuthentication () If (authentication! = null & &! trustResolver.isAnonymous (authentication)) {/ / The user has been authenticated during the current request, so call the / / session strategy try {sessionAuthenticationStrategy.onAuthentication (authentication, request, response) } catch (SessionAuthenticationException e) {/ / The session strategy can reject the authentication logger.debug ("SessionAuthenticationStrategy rejected the authentication object", e); SecurityContextHolder.clearContext () FailureHandler.onAuthenticationFailure (request, response, e); return;} / / Eagerly save the security context to make it available for any possible / / re-entrant / / requests which may occur before the current request completes. / / SEC-1396. SecurityContextRepository.saveContext (SecurityContextHolder.getContext (), request, response);} else {/ / No security context or authentication present. Check for a session / / timeout if (request.getRequestedSessionId ()! = null & &! request.isRequestedSessionIdValid ()) {if (logger.isDebugEnabled ()) {logger.debug ("Requested session ID" + request.getRequestedSessionId () + "is invalid.") } if (invalidSessionStrategy! = null) {invalidSessionStrategy .onInvalidSessionDetected (request, response); return Chain.doFilter (request, response);}.}

From the source code, we can analyze the related functions of SessionManagementFilter:

SecurityContextRepository limits the number of sessions opened by the same user

SessionAuthenticationStrategy prevents session-fixation protection attack (protects non-anonymous users)

2.10.ExceptionTranslationFilterpublic class ExceptionTranslationFilter extends GenericFilterBean {. Public void doFilter (ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; try {chain.doFilter (request, response); logger.debug ("Chain processed normally");} catch (IOException ex) {throw ex } catch (Exception ex) {/ / Try to extract a SpringSecurityException from the stacktrace Throwable [] causeChain = throwableAnalyzer.determineCauseChain (ex); RuntimeException ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType (AuthenticationException.class, causeChain); if (ase = = null) {ase = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType (AccessDeniedException.class, causeChain) } if (ase! = null) {handleSpringSecurityException (request, response, chain, ase);} else {/ / Rethrow ServletExceptions and RuntimeExceptions as-is if (ex instanceof ServletException) {throw (ServletException) ex } else if (ex instanceof RuntimeException) {throw (RuntimeException) ex;} / / Wrap other Exceptions. This shouldn't actually happen / / as we've already covered all the possibilities for doFilter throw new RuntimeException (ex);}}.}

From the source code, we can analyze the related functions of ExceptionTranslationFilter:

The ExceptionTranslationFilter exception translation filter is located behind the entire springSecurityFilterChain and is used to convert exceptions that occur throughout the link.

The function of this filter is to handle the exception thrown by FilterSecurityInterceptor, and then redirect the request to the corresponding page or return the corresponding response error code

2.11.FilterSecurityInterceptorpublic class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {. Public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {FilterInvocation fi = new FilterInvocation (request, response, chain); invoke (fi);} public FilterInvocationSecurityMetadataSource getSecurityMetadataSource () {return this.securityMetadataSource;} public SecurityMetadataSource obtainSecurityMetadataSource () {return this.securityMetadataSource } public void invoke (FilterInvocation fi) throws IOException, ServletException {if ((fi.getRequest ()! = null) & & (fi.getRequest (). GetAttribute (FILTER_APPLIED)! = null) & & observeOncePerRequest) {/ / filter already applied to this request and user wants us to observe / / once-per-request handling So don't re-do security checking fi.getChain () .doFilter (fi.getRequest (), fi.getResponse ()) } else {/ / first time this request being called, so perform security checking if (fi.getRequest ()! = null) {fi.getRequest () .setAttribute (FILTER_APPLIED, Boolean.TRUE);} InterceptorStatusToken token = super.beforeInvocation (fi) Try {fi.getChain () .doFilter (fi.getRequest (), fi.getResponse ());} finally {super.finallyInvocation (token);} super.afterInvocation (token, null);}}.}

From the source code, we can analyze the related functions of FilterSecurityInterceptor:

Get authorization information for access to configured resources

Determine whether the user has permissions based on the user information stored in SecurityContextHolder

Some of the main implementation functions are in its parent class AbstractSecurityInterceptor

2.12.UsernamePasswordAuthenticationFilterpublic class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {. Public Authentication attemptAuthentication (HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (postOnly & &! request.getMethod (). Equals ("POST")) {throw new AuthenticationServiceException ("Authentication method not supported:" + request.getMethod ());} String username = obtainUsername (request); String password = obtainPassword (request) If (username = = null) {username = ";} if (password = = null) {password =";} username = username.trim (); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken (username, password) / / Allow subclasses to set the "details" property setDetails (request, authRequest); return this.getAuthenticationManager (). Authenticate (authRequest);}.}

From the source code, we can analyze the related functions of UsernamePasswordAuthenticationFilter:

Form authentication is one of the most commonly used authentication methods, and one of the most intuitive business scenarios is to allow users to enter a user name and password into the form to log in, while the UsernamePasswordAuthenticationFilter behind this plays a vital role in the whole Spring Security authentication system.

At this point, I believe you have a deeper understanding of "what is the core filter chain of Spring Security". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report