后面通过三篇文章,从底层代码的角度剖析了SpringSecurity的初始化过程。

接下来咱们就要具体看一下,Spring Security的平安过滤器初始化、拆卸好之后,到底是怎么工作的。

还是按图索骥

上面咱们简略从底层源码剖析一下,申请是怎么调用到Spring Security的平安过滤器的。

Spring Security平安过滤器工作原理

后面文章曾经剖析过DelegatinFilterProxy调用到FilterChainProxy的源码,所以咱们明天间接从FilterChainProxy的doFilter办法开始:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)            throws IOException, ServletException {        boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;        if (!clearContext) {            doFilterInternal(request, response, chain);            return;        }        try {            request.setAttribute(FILTER_APPLIED, Boolean.TRUE);            doFilterInternal(request, response, chain);        }        catch (RequestRejectedException ex) {            this.requestRejectedHandler.handle((HttpServletRequest) request, (HttpServletResponse) response, ex);        }        finally {            SecurityContextHolder.clearContext();            request.removeAttribute(FILTER_APPLIED);        }    }

间接看doInternalFilter办法。首先调用getFilters办法:

private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)            throws IOException, ServletException {        FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest) request);        HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse) response);        List<Filter> filters = getFilters(firewallRequest);        //省略局部源码        VirtualFilterChain virtualFilterChain = new VirtualFilterChain(firewallRequest, chain, filters);        virtualFilterChain.doFilter(firewallRequest, firewallResponse);    }

这个getFilters办法的源码就不贴出了,有趣味的同学关上源码看一下,非常简单:从FilterChainProxy持有的DefaultSecurityFilterChain对象中获取到filters,这个filters就是Spring Security初始化过程中拆卸好的Spring Security的各平安过滤器。

之后用平安过滤器组装一个叫virtualFilterChain的外部对象,这个外部对象次要就是为了持有Spring Security的平安过滤器的,而后通过调用virtualFilterChain的doFilter办法,一一调用Spring Security的平安过滤器。

Spring Security平安过滤器

Spring Security有不少平安过滤器(下图,SprigBoot默认启动的就有15个),咱们次要关注与用户身份认证及鉴权密切相关的、或者我的项目中比拟常见的过滤器,其余过滤器临时略过或一笔带过。

1.WebAsyncManagerIntegrationFilter

web异步集成过滤器,创立SecurityContextCallableProcessingInterceptor并注册到WebAsyncManager中。

具体作用略。

2.SecurityContextPersistenceFilter

将蕴含认证信息的SecurityContextHolder在认证之后保存起来(保留在SecurityContextRepository中,个别状况下是session),并且在每次申请发动、认证产生之前从SecurityContextRepository获取进去搁置到SecurityContextHolder中。

SecurityContextPersistenceFilter是Spring Security的第2个平安过滤器,在所有认证过滤器之前执行。

SecurityContextPersistenceFilter首先从session中(默认状况下)获取SecurityContext,如果session中没有SecurityContext则创立一个空的SecurityContext,之后将SecurityContext存入SecurityContextHolder。

默认状况下SecurityContextHolder通过ThreadLocalSecurityContextHolderStrategy(也就是应用ThreadLocal)存储SecurityContext。

最初,在申请执行实现之后,将SecurityContextHolder持有的SecurityContext保存起来(默认存储在session中),并清空SecurityContextHolder。

这样,通过SecurityContextPersistenceFilter过滤器,Spring Security就能够在其余平安过滤器执行之前,从session中获取以后用户的认证信息,因此在后续用户认证操作执行之前、如果以后用户曾经实现了认证、则能够确保可能获取到以后用户的认证信息,因而可能通过后续的用户认证过程!!!

3.HeaderWirterFilter

写Response头信息以便达到对Http Response的相应管制。

HeaderWirterFilter初始化的时候会注册如下HeadWriter:

这些HeadWriter会帮忙咱们对Http Response Header做一些默认设置,比方CacheControlHeadersWriter会执行如下操作:

    private static List<Header> createHeaders() {        List<Header> headers = new ArrayList<>(3);        headers.add(new Header(CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"));        headers.add(new Header(PRAGMA, "no-cache"));        headers.add(new Header(EXPIRES, "0"));        return headers;    }

个别状况下,咱们的利用须要这样的设置,不应用Spring Security的话咱们的利用须要手动设置,应用了Spring Security的话,就不须要多此一举了。

4.CsrfFilter

跨域申请过滤器,次要作用是防跨域攻打。

5.LogoutFilter

解决Logout申请,并导航到logout页面。

6.UsernamePasswordAuthenticationFilter

这是Spring Security用户认证的默认实现。

他有一个叫AbstractAuthenticationProcessingFilter的父类,doFilter办法就是在父类实现的。

只针对post办法的/login申请失效,所以如果咱们要应用该过滤器的话,利用的登录必须是post办法的/login申请。

Spring Security的登录认证过程就是通过这个过滤器实现的,绝对还比较复杂,篇幅关系明天就不开展了,明天的次要指标是要搞清楚他的作用。

首先验证以后申请是否须要登录认证,如前所述,如果申请不是post的/login的话,则不做登录认证。

从request中获取的username,password创立UsernamePasswordAuthenticationToken对象进行认证。

认证的过程其实就是咱们验证用户名、明码的过程,SpringSecurity有一个默认的用户名、明码认证实现,是在系统启动过程中为用户user生成UUID并打印在控制台、通过用户名user、明码为该UUID实现认证。咱们能够实现本人的认证,比方通过数据库的用户名、明码形式实现认证。

认证通过则将认证信息存储在SecurityContext中,如果认证失败(比方用户名明码谬误等)则清空SecurityContext并记录相干异样。

7.DefaultLoginPageGeneratingFilter

为/login申请生成登录页面。

8.DefaultLogoutPageGeneratingFilter

导航到登出页面。

9.BasicAuthenticationFilter

对于采纳Basic Authentication的申请执行认证。Basi Authentication指的是申请头中蕴含:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

其中Basic后是采纳base64编码的明码信息。

不太理解、没有应用过这种认证形式,略过。

10.RequestCacheAwareFilter

次要作用是缓存以后申请信息,以便在因为认证未通过无奈执行该申请的状况下,后续认证通过后从新发动该申请。

11.SecurityContextHolderAwareRequestFilter

用于对request做一层包装,以便反对Servlet中平安相干的API调用。

12.AnonymousAuthenticationFilter

匿名过滤器,从SecurityContextHolder获取认证信息,如果通过了后面的SecurityContextPersistenceFilter、以及UsernamePasswordAuthenticationFilter解决后,SecurityContextHolder中还是没有认证信息的话,阐明以后申请并没有通过Spring Security的平安认证,则创立一个匿名认证信息存储在SecurityContextHolder中。

13.SessionManagementFilter

session治理的过滤器,次要为了避免session固化攻打、以及实现登录并发管制性能。

14.ExceptionTranslationFilter

实现异样管制的平安过滤器,留神该过滤器对异样的解决是平安过滤器链执行实现、返回之后。所以,上面的第14个、第15个过滤器执行过程中的异样,也能被本过滤器捕捉并解决。

次要解决Spring Security的两类异样:

  1. AuthenticationException
  2. AccessDeniedException
    并将异样交给相应的异样处理器进行解决,比方AccessDeniedException异样处理器通常会通过response返回前端403谬误。

15.FilterSecurityInterceptor

Spring Security次要平安过滤器的执行曾经靠近序幕,然而这个FilterSecurityInterceptor是重头戏。

FilterSecurityInterceptor次要实现如下工作:

  1. 解析以后申请的平安配置,次要包含:permitAll、authenticated、denyAll、anonymous等。
  2. 从SecurityContextHolder获取平安认证信息。
  3. 依据以后申请的平安配置信息及以后用户的平安认证信息进行认证投票,其实就是判断获取到的以后用户的平安认证信息是否合乎配置的平安认证需要,合乎的话则通过认证,不合乎的话抛出accesssdeny异样。

之所以说FilterSecurityInterceptor是Spring Security平安过滤器的重头戏,是因为咱们依据我的项目的具体需要、针对不同申请配置好的平安认证规范的解析是FilterSecurityInterceptor实现的,解析之后查看以后用户是否满足申请所须要的平安要求也是FilterSecurityInterceptor实现的。

如果以后用户认证信息不满足以后申请的平安需要,比方匿名用户拜访/helloworld、/helloworld配置为authenticated的话,FilterSecurityInterceptor会抛出accesssdeny异样,最终经ExceptionTranslationFilter解决之后前台页面会收到403错误信息。

总结

Spring security次要平安过滤器的根本工作原理剖析结束,其实每一个平安过滤器的底层工作细节都能够独自写一篇文章进行代码级的剖析。然而一般来讲,对于绝对简单一点的常识,入门学习的时候太过细节的剖析会影响到对整体框架的了解,Spring Security绝对来讲比拟负责,因而适宜这一准则。

上一篇 Spring Security的初始化过程(3)