Spring Security核心过滤器链是什么

发布时间:2021-12-02 11:44:50 作者:iii
来源:亿速云 阅读:130

本篇内容主要讲解“Spring Security核心过滤器链是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring Security核心过滤器链是什么”吧!

一、Filter Chain 图解

在配置了spring security了之后,会在运行项目的时候,DefaultSecurityFilterChain会输出相关log:

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

输出以下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
]

也可以从Debug进行查看:

Spring Security核心过滤器链是什么

二、过滤器逐一解析

在解析前,先说说两个至关重要的类:OncePerRequestFilter和GenericFilterBean,在过滤器链的过滤器中,或多或少间接或直接继承到

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);
    }
  }

从源码中,我们可以分析出WebAsyncManagerIntegrationFilter相关功能:

2.2.SecurityContextPersistenceFilter

public 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");
                }
            }
        }
            ......
    }

从源码中,我们可以分析出SecurityContextPersistenceFilter相关功能:

2.3.HeaderWriterFilter

public 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);
    }
}

从源码中,我们可以分析HeaderWriterFilter相关功能:

2.4.CsrfFilter

public 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);
    }
        ......
}

从源码中,我们可以分析出CsrfFilter相关功能:

2.5.LogoutFilter

public 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);
    }
    ......
}

从源码中,我们可以分析出LogoutFilter相关功能:

2.6.RequestCacheAwareFilter

public 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);
    }
}

从源码中,我们可以分析出RequestCacheAwareFilter相关功能:

通过HttpSessionRequestCache内部维护了一个RequestCache,用于缓存HttpServletRequest

2.7.SecurityContextHolderAwareRequestFilter

public 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);
    }
    ......
}

从源码中,我们可以分析出SecurityContextHolderAwareRequestFilter相关功能:

2.8.AnonymousAuthenticationFilter

public 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);
    }
    ......
}

从源码中,我们可以分析出AnonymousAuthenticationFilter相关功能:

2.9.SessionManagementFilter

public 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);
    }
    ......
}

从源码中,我们可以分析出SessionManagementFilter相关功能:

2.10.ExceptionTranslationFilter

public 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);
            }
        }
    }
    ......
}

从源码中,我们可以分析出ExceptionTranslationFilter相关功能:

2.11.FilterSecurityInterceptor

public 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);
            }
    }
    ......
}

从源码中,我们可以分析出FilterSecurityInterceptor相关功能:

2.12.UsernamePasswordAuthenticationFilter

public 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);
    }
    ......
}

从源码中,我们可以分析出UsernamePasswordAuthenticationFilter相关功能:

到此,相信大家对“Spring Security核心过滤器链是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

推荐阅读:
  1. Spring Security原理是什么
  2. Spring Security常用过滤器实例解析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring security

上一篇:如何配置Flutter+Idea环境

下一篇:tk.Mybatis插入数据获取Id怎么实现

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》