最近在公司的项目中使用了spring security框架,所以有机会来学习一下,公司的项目是使用springboot搭建 springBoot版本1.59

spring security 版本4.2.3

(个人理解可能会有偏差,希望有不正确之处,大家能够指出来,共同探讨交流。)

目录

一、Spring security框架简介

1、简介

2、框架原理

3、框架的核心组件

二、自定义安全配置的加载机制

1、前提 基于自身业务需要

2、WebSecurityConfiguration类

3、AbstractSecurityBuilder类

4、举例说明如何将一个Configurer转换为filter

三、用户登录的验证和授权过程


一、Spring security框架简介

1、简介

一个能够为基于Spring的企业应用系统提供声明式的安全訪问控制解决方式的安全框架(简单说是对访问权限进行控制嘛),应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。   spring security的主要核心功能为 认证和授权,所有的架构也是基于这两个核心功能去实现的。

2、框架原理

众所周知 想要对对Web资源进行保护,最好的办法莫过于Filter,要想对方法调用进行保护,最好的办法莫过于AOP。所以springSecurity在我们进行用户认证以及授予权限的时候,通过各种各样的拦截器来控制权限的访问,从而实现安全。

        如下为其主要过滤器

  1. WebAsyncManagerIntegrationFilter
  2. SecurityContextPersistenceFilter
  3. HeaderWriterFilter
  4. CorsFilter
  5. LogoutFilter
  6. RequestCacheAwareFilter
  7. SecurityContextHolderAwareRequestFilter
  8. AnonymousAuthenticationFilter
  9. SessionManagementFilter
  10. ExceptionTranslationFilter
  11. FilterSecurityInterceptor
  12. UsernamePasswordAuthenticationFilter
  13. BasicAuthenticationFilter

3、框架的核心组件

  1. SecurityContextHolder:提供对SecurityContext的访问
  2. SecurityContext,:持有Authentication对象和其他可能需要的信息
  3. AuthenticationManager 其中可以包含多个AuthenticationProvider
  4. ProviderManager对象为AuthenticationManager接口的实现类
  5. AuthenticationProvider 主要用来进行认证操作的类 调用其中的authenticate()方法去进行认证操作
  6. Authentication:Spring Security方式的认证主体
  7. GrantedAuthority:对认证主题的应用层面的授权,含当前用户的权限信息,通常使用角色表示
  8. UserDetails:构建Authentication对象必须的信息,可以自定义,可能需要访问DB得到
  9. UserDetailsService:通过username构建UserDetails对象,通过loadUserByUsername根据userName获取UserDetail对象 (可以在这里基于自身业务进行自定义的实现  如通过数据库,xml,缓存获取等)

二、自定义安全配置的加载机制

1、前提 基于自身业务需要

有关springSecrity安全框架的理解参考:springSecurity安全框架介绍

自定义了一个springSecurity安全框架的配置类 继承WebSecurityConfigurerAdapter,重写其中的方法configure,但是并不清楚自定义的类是如何被加载并起到作用,这里一步步通过debug来了解其中的加载原理。

其实在我们实现该类后,在web容器启动的过程中该类实例对象会被WebSecurityConfiguration类处理。

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired
private AccessDeniedHandler accessDeniedHandler; @Autowired
private CustAuthenticationProvider custAuthenticationProvider; // roles admin allow to access /admin/**
// roles user allow to access /user/**
// custom 403 access denied handler
//重写了其中的configure()方法设置了不同url的不同访问权限
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/home", "/about","/img/*").permitAll()
.antMatchers("/admin/**","/upload/**").hasAnyRole("ADMIN")
.antMatchers("/order/**").hasAnyRole("USER","ADMIN")
.antMatchers("/room/**").hasAnyRole("USER","ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
} // create two users, admin and user
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { // auth.inMemoryAuthentication()
// .withUser("user").password("user").roles("USER")
// .and()
// .withUser("admin").password("admin").roles("ADMIN"); // auth.jdbcAuthentication() auth.authenticationProvider(custAuthenticationProvider);
}

2、WebSecurityConfiguration类

@Configuration
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private WebSecurity webSecurity;
private Boolean debugEnabled;
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
private ClassLoader beanClassLoader; ...省略部分代码 @Bean(
name = {"springSecurityFilterChain"}
)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = this.webSecurityConfigurers != null
&& !this.webSecurityConfigurers.isEmpty();
if(!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)
this.objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
} return (Filter)this.webSecurity.build();
} /*1、先执行该方法将我们自定义springSecurity配置实例
(可能还有系统默认的有关安全的配置实例 ) 配置实例中含有我们自定义业务的权限控制配置信息
放入到该对象的list数组中webSecurityConfigurers中
使用@Value注解来将实例对象作为形参注入
*/
@Autowired(
required = false
)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object>
objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}")
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception { //创建一个webSecurity对象
this.webSecurity = (WebSecurity)objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if(this.debugEnabled != null) {
this.webSecurity.debug(this.debugEnabled.booleanValue());
} //对所有配置类的实例进行排序
Collections.sort(webSecurityConfigurers, WebSecurityConfiguration.AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null; //迭代所有配置类的实例 判断其order必须唯一
Iterator var5;
SecurityConfigurer config;
for(var5 = webSecurityConfigurers.iterator(); var5.hasNext(); previousConfig = config) {
config = (SecurityConfigurer)var5.next();
Integer order = Integer.valueOf(WebSecurityConfiguration.AnnotationAwareOrderComparator.lookupOrder(config));
if(previousOrder != null && previousOrder.equals(order)) {
throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order + " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
} previousOrder = order;
} //将所有的配置实例添加到创建的webSecutity对象中
var5 = webSecurityConfigurers.iterator(); while(var5.hasNext()) {
config = (SecurityConfigurer)var5.next();
this.webSecurity.apply(config);
}
//将webSercurityConfigures 实例放入该对象的webSecurityConfigurers属性中
this.webSecurityConfigurers = webSecurityConfigurers;
} }

2.1、 setFilterChainProxySecurityConfigurer()方法

@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers

该参数webSecurityConfigurers会将所有的配置实例放入该形参中

该方法中 主要执行如下

1、创建webSecurity对象

2、主要检验了配置实例的order顺序(order唯一 否则会报错)

3、将所有的配置实例存放进入到webSecurity对象中,其中配置实例中含有我们自定义业务的权限控制配置信息

2.2、springSecurityFilterChain()方法

调用springSecurityFilterChain()方法,这个方法会判断我们上一个方法中有没有获取到webSecurityConfigurers,没有的话这边会创建一个WebSecurityConfigurerAdapter实例,并追加到websecurity中。接着调用websecurity的build方法。实际调用的是websecurity的父类AbstractSecurityBuilder的build方法 ,最终返回一个名称为springSecurityFilterChain的过滤器链。里面有众多Filter(springSecurity其实就是依靠很多的Filter来拦截url从而实现权限的控制的安全框架)

3、AbstractSecurityBuilder类

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
private AtomicBoolean building = new AtomicBoolean();
private O object; //调用build方法来返回过滤器链,还是调用SecurityBuilder的dobuild()方法 public final O build() throws Exception {
if(this.building.compareAndSet(false, true)) {
this.object = this.doBuild();
return this.object;
} else {
throw new AlreadyBuiltException("This object has already been built");
}
} //...省略部分代码
}

3.1 调用子类的doBuild()方法

public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>> extends AbstractSecurityBuilder<O> {
private final Log logger;
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers;
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing;
private final Map<Class<? extends Object>, Object> sharedObjects;
private final boolean allowConfigurersOfSameType;
private AbstractConfiguredSecurityBuilder.BuildState buildState;
private ObjectPostProcessor<Object> objectPostProcessor; //doBuild()核心方法 init(),configure(),perFormBuild()
protected final O doBuild() throws Exception {
LinkedHashMap var1 = this.configurers;
synchronized(this.configurers) {
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.INITIALIZING;
this.beforeInit();
this.init();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.CONFIGURING;
this.beforeConfigure();
this.configure();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILDING;
O result = this.performBuild();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILT;
return result;
}
} protected abstract O performBuild() throws Exception; //调用init方法 调用配置类WebSecurityConfigurerAdapter的init()方法
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = this.getConfigurers();
Iterator var2 = configurers.iterator(); SecurityConfigurer configurer;
while(var2.hasNext()) {
configurer = (SecurityConfigurer)var2.next();
configurer.init(this);
} var2 = this.configurersAddedInInitializing.iterator(); while(var2.hasNext()) {
configurer = (SecurityConfigurer)var2.next();
configurer.init(this);
} } private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = this.getConfigurers();
Iterator var2 = configurers.iterator(); while(var2.hasNext()) {
SecurityConfigurer<O, B> configurer = (SecurityConfigurer)var2.next();
configurer.configure(this);
} } private Collection<SecurityConfigurer<O, B>> getConfigurers() {
List<SecurityConfigurer<O, B>> result = new ArrayList();
Iterator var2 = this.configurers.values().iterator(); while(var2.hasNext()) {
List<SecurityConfigurer<O, B>> configs = (List)var2.next();
result.addAll(configs);
} return result;
} //...省略部分代码
}

3.2 先调用本类的init()方法

build过程主要分三步,init->configure->peformBuild

  • 1  init方法做了两件事,一个就是调用getHttp()方法获取一个http实例,并通过web.addSecurityFilterChainBuilder方法把获取到的实例赋值给WebSecurity的securityFilterChainBuilders属性,这个属性在我们执行build的时候会用到,第二个就是为WebSecurity追加了一个postBuildAction,在build都完成后从http中拿出FilterSecurityInterceptor对象并赋值给WebSecurity。
  • 2  getHttp()方法,这个方法在当我们使用默认配置时(大多数情况下)会为我们追加各种SecurityConfigurer的具体实现类到httpSecurity中,如exceptionHandling()方法会追加一个ExceptionHandlingConfigurer,sessionManagement()方法会追加一个SessionManagementConfigurer,securityContext()方法会追加一个SecurityContextConfigurer对象,这些SecurityConfigurer的具体实现类最终会为我们配置各种具体的filter。
  • 3 另外getHttp()方法的最后会调用configure(http),这个方法也是我们继承WebSecurityConfigurerAdapter类后最可能会重写的方法 。
  • 4 configure(HttpSecurity http)方法,默认的configure(HttpSecurity http)方法继续向httpSecurity类中追加SecurityConfigurer的具体实现类,如authorizeRequests()方法追加一个ExpressionUrlAuthorizationConfigurer,formLogin()方法追加一个FormLoginConfigurer。 其中ExpressionUrlAuthorizationConfigurer这个实现类比较重要,因为他会给我们创建一个非常重要的对象FilterSecurityInterceptor对象,FormLoginConfigurer对象比较简单,但是也会为我们提供一个在安全认证过程中经常用到会用的一个Filter:UsernamePasswordAuthenticationFilter。

以上三个方法就是WebSecurityConfigurerAdapter类中init方法的主要逻辑,

public abstract class WebSecurityConfigurerAdapter implements
WebSecurityConfigurer<WebSecurity> { public void init(final WebSecurity web) throws Exception {
final HttpSecurity http = this.getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = (FilterSecurityInterceptor)http.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
} protected final HttpSecurity getHttp() throws Exception {
if(this.http != null) {
return this.http;
} else {
DefaultAuthenticationEventPublisher eventPublisher = (DefaultAuthenticationEventPublisher)this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher()); //添加认证的事件的发布者
this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
//获取AuthenticationManager对象其中一至多个进行认证处理的对象实例,后面会进行讲解
AuthenticationManager authenticationManager = this.authenticationManager();
this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
Map<Class<? extends Object>, Object> sharedObjects = this.createSharedObjects();
this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
if(!this.disableDefaults) {
((HttpSecurity)((DefaultLoginPageConfigurer)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)this.http.csrf().and()).addFilter(new WebAsyncManagerIntegrationFilter()).exceptionHandling().and()).headers().and()).sessionManagement().and()).securityContext().and()).requestCache().and()).anonymous().and()).servletApi().and()).apply(new DefaultLoginPageConfigurer())).and()).logout();
ClassLoader classLoader = this.context.getClassLoader();
List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
Iterator var6 = defaultHttpConfigurers.iterator(); while(var6.hasNext()) {
AbstractHttpConfigurer configurer = (AbstractHttpConfigurer)var6.next();
this.http.apply(configurer);
}
} //最终调用我们的继承的WebSecurityConfigurerAdapter中重写的configure()
//将我们业务相关的权限配置规则信息进行初始化操作
this.configure(this.http);
return this.http;
}
} protected AuthenticationManager authenticationManager() throws Exception {
if(!this.authenticationManagerInitialized) {
this.configure(this.localConfigureAuthenticationBldr);
if(this.disableLocalConfigureAuthenticationBldr) {
this.authenticationManager = this.authenticationConfiguration.getAuthenticationManager();
} else {
this.authenticationManager = (AuthenticationManager)this.localConfigureAuthenticationBldr.build();
} this.authenticationManagerInitialized = true;
} return this.authenticationManager;
} }

3.3、第二步configure

  • configure方法最终也调用到了WebSecurityConfigurerAdapter的configure(WebSecurity web)方法,默认实现中这个是一个空方法,具体应用中也经常重写这个方法来实现特定需求。

3.4、第三步 peformBuild

  • 具体的实现逻辑在WebSecurity类中
  • 这个方法中最主要的任务就是遍历securityFilterChainBuilders属性中的SecurityBuilder对象,并调用他的build方法。 

    这个securityFilterChainBuilders属性我们前面也有提到过,就是在WebSecurityConfigurerAdapter类的init方法中获取http后赋值给了WebSecurity。因此这个地方就是调用httpSecurity的build方法。
  • httpSecurity的build方式向其中追加一个个过滤器

public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder<Filter>, ApplicationContextAware { ...省略部分代码
<span class="hljs-comment">//调用该方法通过securityFilterChainBuilder.build()方法来创建securityFilter过滤器</span>
<span class="hljs-comment">//并添加到securityFilterChains对象中,包装成FilterChainProxy 返回</span>
<span class="hljs-function"><span class="hljs-keyword">protected</span> Filter <span class="hljs-title">performBuild</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{
Assert.state(!<span class="hljs-keyword">this</span>.securityFilterChainBuilders.isEmpty(), <span class="hljs-string">"At least one SecurityBuilder&lt;? extends SecurityFilterChain&gt; needs to be specified. Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. More advanced users can invoke "</span> + WebSecurity.class.getSimpleName() + <span class="hljs-string">".addSecurityFilterChainBuilder directly"</span>);
<span class="hljs-keyword">int</span> chainSize = <span class="hljs-keyword">this</span>.ignoredRequests.size() + <span class="hljs-keyword">this</span>.securityFilterChainBuilders.size();
List&lt;SecurityFilterChain&gt; securityFilterChains = <span class="hljs-keyword">new</span> ArrayList(chainSize);
Iterator var3 = <span class="hljs-keyword">this</span>.ignoredRequests.iterator(); <span class="hljs-keyword">while</span>(var3.hasNext()) {
RequestMatcher ignoredRequest = (RequestMatcher)var3.next();
securityFilterChains.add(<span class="hljs-keyword">new</span> DefaultSecurityFilterChain(ignoredRequest, <span class="hljs-keyword">new</span> Filter[<span class="hljs-number">0</span>]));
} var3 = <span class="hljs-keyword">this</span>.securityFilterChainBuilders.iterator(); <span class="hljs-keyword">while</span>(var3.hasNext()) {
SecurityBuilder&lt;? extends SecurityFilterChain&gt; securityFilterChainBuilder = (SecurityBuilder)var3.next();
securityFilterChains.add(securityFilterChainBuilder.build());
} FilterChainProxy filterChainProxy = <span class="hljs-keyword">new</span> FilterChainProxy(securityFilterChains);
<span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.httpFirewall != <span class="hljs-keyword">null</span>) {
filterChainProxy.setFirewall(<span class="hljs-keyword">this</span>.httpFirewall);
} filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
<span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.debugEnabled) {
<span class="hljs-keyword">this</span>.logger.warn(<span class="hljs-string">"\n\n********************************************************************\n********** Security debugging is enabled. *************\n********** This may include sensitive information. *************\n********** Do not use in a production system! *************\n********************************************************************\n\n"</span>);
result = <span class="hljs-keyword">new</span> DebugFilter(filterChainProxy);
} <span class="hljs-keyword">this</span>.postBuildAction.run();
<span class="hljs-keyword">return</span> (Filter)result;
}

}

4、举例说明如何将一个Configurer转换为filter

ExpressionUrlAuthorizationConfigurer的继承关系 

ExpressionUrlAuthorizationConfigurer->AbstractInterceptUrlConfigurer->AbstractHttpConfigurer->SecurityConfigurerAdapter->SecurityConfigurer 

对应的init方法在SecurityConfigurerAdapter类中,是个空实现,什么也没有做,configure方法在SecurityConfigurerAdapter类中也有一个空实现,在AbstractInterceptUrlConfigurer类中进行了重写

Abstractintercepturlconfigurer.java代码

@Override  
    public void configure(H http) throws Exception {  
        FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);  
        if (metadataSource == null) {  
            return;  
        }  
        FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(  
                http, metadataSource, http.getSharedObject(AuthenticationManager.class));  
        if (filterSecurityInterceptorOncePerRequest != null) {  
            securityInterceptor  
                    .setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);  
        }  
        securityInterceptor = postProcess(securityInterceptor);  
        http.addFilter(securityInterceptor);  
        http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);  
    }  
...  
private AccessDecisionManager createDefaultAccessDecisionManager(H http) {  
        AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));  
        return postProcess(result);  
    }  
...  
private FilterSecurityInterceptor createFilterSecurityInterceptor(H http,  
            FilterInvocationSecurityMetadataSource metadataSource,  
            AuthenticationManager authenticationManager) throws Exception {  
        FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();  
        securityInterceptor.setSecurityMetadataSource(metadataSource);  
        securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http));  
        securityInterceptor.setAuthenticationManager(authenticationManager);  
        securityInterceptor.afterPropertiesSet();  
        return securityInterceptor;  
    }  

4.1、 在这个类的configure中创建了一个FilterSecurityInterceptor,并且也可以明确看到spring security默认给我们创建的AccessDecisionManager是AffirmativeBased。 

4.2、.最后再看下HttpSecurity类执行build的最后一步 performBuild,这个方法就是在HttpSecurity中实现的

Httpsecurity.java代码

@Override  
    protected DefaultSecurityFilterChain performBuild() throws Exception {  
        Collections.sort(filters, comparator);  
        return new DefaultSecurityFilterChain(requestMatcher, filters);  
    }  

可以看到,这个类只是把我们追加到HttpSecurity中的security进行了排序,用的排序类是FilterComparator,从而保证我们的filter按照正确的顺序执行。接着将filters构建成filterChian返回。在前面WebSecurity的performBuild方法中,这个返回值会被包装成FilterChainProxy,并作为WebSecurity的build方法的放回值。从而以springSecurityFilterChain这个名称注册到springContext中(在WebSecurityConfiguration中做的) 

4.3.在WebSecurity的performBuild方法的最后一步还执行了一个postBuildAction.run,这个方法也是spring security给我们提供的一个hooks,可以在build完成后再做一些事情,比如我们在WebSecurityConfigurerAdapter类的init方法中我们利用这个hook在构建完成后将FilterSecurityInterceptor赋值给了webSecurity类的filterSecurityInterceptor属性

三、用户登录的验证和授权过程

1、用户一次完整的登录验证和授权,是一个请求经过 层层拦截器从而实现权限控制,整个web端配置为DelegatingFilterProxy(springSecurity的委托过滤其代理类 ),它并不实现真正的过滤,而是所有过滤器链的代理类,真正执行拦截处理的是由spring 容器管理的个个filter bean组成的filterChain.

调用实际的FilterChainProxy 的doFilterInternal()方法 去获取所有的拦截器并进行过滤处理如下是DelegatingFilterProxy的doFilter()方法

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
Filter delegateToUse = this.delegate;
if(delegateToUse == null) {
Object var5 = this.delegateMonitor;
synchronized(this.delegateMonitor) {
delegateToUse = this.delegate;
if(delegateToUse == null) {
WebApplicationContext wac = this.findWebApplicationContext();
if(wac == null) {
throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");
} delegateToUse = this.initDelegate(wac);
} this.delegate = delegateToUse;
}
} //调用实际的FilterChainProxy 的doFilterInternal()方法 去获取所有的拦截器并进行过滤处理
this.invokeDelegate(delegateToUse, request, response, filterChain);
}

调用实际的FilterChainProxy 的doFilter()方法 去获取所有的拦截器并进行过滤处理。

2、FilterChainProxy类

最终调用FilterChainProxy 的doFilterInternal()方法,获取所有的过滤器实例

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if(clearContext) {
try {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
//doFilter 调用doFilterInternal方法
this.doFilterInternal(request, response, chain);
} finally {
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
} else {
this.doFilterInternal(request, response, chain);
} } private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FirewalledRequest fwRequest = this.firewall.getFirewalledRequest((HttpServletRequest)request);
HttpServletResponse fwResponse = this.firewall.getFirewalledResponse((HttpServletResponse)response);
//过去所有的过滤器
List<Filter> filters = this.getFilters((HttpServletRequest)fwRequest);
if(filters != null && filters.size() != 0) {
FilterChainProxy.VirtualFilterChain vfc = new FilterChainProxy.VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
} else {
if(logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(fwRequest) + (filters == null?" has no matching filters":" has an empty filter list"));
} fwRequest.reset();
chain.doFilter(fwRequest, fwResponse);
}
} private List<Filter> getFilters(HttpServletRequest request) {
//遍历所有的matcher类 如果支持就继续获取
Iterator var2 = this.filterChains.iterator(); SecurityFilterChain chain;
do {
if(!var2.hasNext()) {
return null;
} chain = (SecurityFilterChain)var2.next();
} while(!chain.matches(request));
//后去匹配中的所有过滤器
return chain.getFilters();
}

如上 其实是获取到本次请求的所有filter 并安装指定顺序进行执行doFilter()方法

这是笔者本次业务请求所要执行的所有过滤器

  1. WebAsyncManagerIntegrationFilter
  2. SecurityContextPersistenceFilter
  3. HeaderWriterFilter
  4. LogoutFilter
  5. UsernamePasswordAuthenticationFilter
  6. RequestCacheAwareFilter
  7. SecurityContextHolderAwareRequestFilter
  8. AnonymousAuthenticationFilter
  9. SessionManagementFilter
  10. ExceptionTranslationFilter
  11. FilterSecurityInterceptor

关于springSecutity拦截器的介绍请参考如下链接地址

https://blog.csdn.net/dushiwodecuo/article/details/78913113

http://blog.didispace.com/xjf-spring-security-4/

https://www.cnblogs.com/HHR-SUN/p/7095720.html

https://blog.csdn.net/zheng963/article/details/50427320

https://blog.csdn.net/m0_37834471/article/details/81142246

https://www.cnblogs.com/mingluosunshan/p/5485259.html

原文地址:https://blog.csdn.net/liushangzaibeijing/article/details/81220610

springSecurity安全框架的学习和原理解读的更多相关文章

  1. Hadoop学习笔记(2) ——解读Hello World

    Hadoop学习笔记(2) ——解读Hello World 上一章中,我们把hadoop下载.安装.运行起来,最后还执行了一个Hello world程序,看到了结果.现在我们就来解读一下这个Hello ...

  2. 读Flask源代码学习Python--config原理

    读Flask源代码学习Python--config原理 个人学习笔记,水平有限.如果理解错误的地方,请大家指出来,谢谢!第一次写文章,发现好累--!. 起因   莫名其妙在第一份工作中使用了从来没有接 ...

  3. Java 并发编程——Executor框架和线程池原理

    Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...

  4. Java 并发编程——Executor框架和线程池原理

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  5. (转)MyBatis框架的学习(二)——MyBatis架构与入门

    http://blog.csdn.net/yerenyuan_pku/article/details/71699515 MyBatis框架的架构 MyBatis框架的架构如下图: 下面作简要概述: S ...

  6. 深入浅出深度学习:原理剖析与python实践_黄安埠(著) pdf

    深入浅出深度学习:原理剖析与python实践 目录: 第1 部分 概要 1 1 绪论 2 1.1 人工智能.机器学习与深度学习的关系 3 1.1.1 人工智能——机器推理 4 1.1.2 机器学习—— ...

  7. go微服务框架kratos学习笔记八 (kratos的依赖注入)

    目录 go微服务框架kratos学习笔记八(kratos的依赖注入) 什么是依赖注入 google wire kratos中的wire Providers injector(注入器) Binding ...

  8. (转) 基于Theano的深度学习(Deep Learning)框架Keras学习随笔-01-FAQ

    特别棒的一篇文章,仍不住转一下,留着以后需要时阅读 基于Theano的深度学习(Deep Learning)框架Keras学习随笔-01-FAQ

  9. jfinal框架教程-学习笔记

    jfinal框架教程-学习笔记 JFinal  是基于 Java  语言的极速  WEB  + ORM  开发框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restfu ...

随机推荐

  1. tablespaces

    select * from user_tablespaces; select username,default_tablespace from user_users;

  2. 阿里云MVP北京闭门会圆满落幕 多把“利剑”助力开发者破阵蜕变

    摘要: 从传统制造业到新零售,从人工智能到新金融,阿里云MVP正在成为中国乃至全球各行各业数字化转型的中坚力量.当这群技术先锋者与阿里核心技术力量汇聚在一起,一场无与伦比的思想碰撞就此展开. 3月21 ...

  3. Spring_通过Bean的Factory配置Bean

    package com.tanlei.bean.FactoryBean; import org.springframework.beans.factory.FactoryBean; public cl ...

  4. Directx11教程(46) alpha blend(3)

    原文:Directx11教程(46) alpha blend(3)       现在我们尝试改变box的贴图,使用一张带alpha的dds文件wirefence.dds, 用directx textu ...

  5. jmeter使用Badboy录制、检查点和参数化

    jmeter使用Badboy录制 1.打开Badboy,在地址栏输入需要录制的网址,如:百度首页

  6. RocksDB 之Write Ahead Log(WAL)

    Overview RocksDB 中有三个基本的数据结构概念:memtable, sstfile 和 logfile memtable 是个内存数据结构,新写入会插入memtable 切回选择性地写入 ...

  7. Ubuntu 16.04下OLSR协议安装教程

    OLSR是根据MANET的要求,在传统的LS(Link state)协议的基础上优化的. OLSR中的关键概念是多点转播(MPRs),MPRs是在广播洪泛的过程中挑选的转发广播的节点.传统的链路状态协 ...

  8. navicat for mysql 在Mac上安装后没有连接列表,就是左边的那一列连接项目怎么办?

    在连接数处打对勾就可以了

  9. Android中使用Apache common ftp进行下载文件

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/birdsaction/article/details/36379201 在Android使用ftp下 ...

  10. @codechef - MGCH3D@ 3D Queries

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 在三维空间内有 N 个不同的点,请计算下面式子的值 Q 次: \ ...