spring-security源码-如何初始化SecurityFilterChain到Servlet
1.Spring-Security系列导航2.spring-security使用-登录(一)3.spring-security使用-自定义数据源(二)4.spring-security使用-更友好的方式扩展登录AuthenticationProvider(三)5.spring-security使用-获得当前用户信息(四)6.spring-security使用-同一个账号只允许登录一次(五)7.spring-security使用-session共享(六)8.spring-security使用-安全防护HttpFirewall(七)9.spring-security使用-权限控制(八)10.spring-security源码-初始化(九)
11.spring-security源码-如何初始化SecurityFilterChain到Servlet
12.spring-security源码-FilterChainProxy13.spring-security源码-Filter之WebAsyncManagerIntegrationFilter(十)14.Spring-security源码-Filter之SecurityContextPersistenceFilter(十一)15.Spring-security源码-Filter之HeaderWriterFilter(十二)16.Spring-security源码-Filter之LogoutFilter(十三)17.Spring-security源码-Filter之UsernamePasswordAuthenticationFilter(十四)18.Spring-security源码-Filter之ConcurrentSessionFilter(十五)19.Spring-security源码-Filter之SessionManagementFilter(十六)20.Spring-security源码-Filter之RememberMeAuthenticationFilter(十七)21.Spring-security源码-Filter之ExceptionTranslationFilter(十八)22.Spring-security源码-Filter之FilterSecurityInterceptor(十九)23.Spring-security源码-注解权限原理(二十)24.Spring-security源码-注解权限原理之MethodSecurityInterceptor(二十一)25.Spring-Security基于源码扩展-一套系统多套登录逻辑(二十二)26.Spring-Security基于源码扩展-自定义登录(二十三)27.Spring-Security基于源码扩展-自定义认证失败返回(二十四)28.Spring-Security基于源码扩展-自定义授权注解(二十五)1.SecurityFilterChain是由HttpSecurty根据各个config配置生成的Filter
SecurityFilterChain是接口,默认实现是由DefaultSecurityFilterChain
SecurityFilterChain只充当描述的作用,描述哪些url走这批filter
public final class DefaultSecurityFilterChain implements SecurityFilterChain { private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class); //匹配url 多套url登录逻辑由这里实现 默认/** 比如/product /user 逻辑相互隔离 private final RequestMatcher requestMatcher; //相关servlet private final List<Filter> filters; public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) { this(requestMatcher, Arrays.asList(filters)); } public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) { if (filters.isEmpty()) { logger.info(LogMessage.format("Will not secure %s", requestMatcher)); } else { logger.info(LogMessage.format("Will secure %s with %s", requestMatcher, filters)); } this.requestMatcher = requestMatcher; this.filters = new ArrayList(filters); } public RequestMatcher getRequestMatcher() { return this.requestMatcher; } public List<Filter> getFilters() { return this.filters; } public boolean matches(HttpServletRequest request) { return this.requestMatcher.matches(request); } public String toString() { return this.getClass().getSimpleName() + " [RequestMatcher=" + this.requestMatcher + ", Filters=" + this.filters + "]"; } }
2.初始化是通过
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration 实现
@AutoConfiguration(after = SecurityAutoConfiguration.class) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(SecurityProperties.class) @ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class }) public class SecurityFilterAutoConfiguration { private static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME; //存在 springSecurityFilterChain @Bean @ConditionalOnBean(name = DEFAULT_FILTER_NAME) public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration( SecurityProperties securityProperties) {
//<3> DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean( DEFAULT_FILTER_NAME); registration.setOrder(securityProperties.getFilter().getOrder()); registration.setDispatcherTypes(getDispatcherTypes(securityProperties)); return registration; } private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) { if (securityProperties.getFilter().getDispatcherTypes() == null) { return null; } return securityProperties.getFilter() .getDispatcherTypes() .stream() .map((type) -> DispatcherType.valueOf(type.name())) .collect(Collectors.toCollection(() -> EnumSet.noneOf(DispatcherType.class))); } }
<3>
委托给DelegatingFilterProxyRegistrationBean
他是 org.springframework.boot.web.servlet.AbstractFilterRegistrationBean的子类,用于注入自定义filter,实现了getFilter方法
org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean#getFilter
public DelegatingFilterProxy getFilter() {
//<4>ServletFilter的实现类 return new DelegatingFilterProxy(this.targetBeanName, this.getWebApplicationContext()) { protected void initFilterBean() throws ServletException { } }; }
<4>
DelegatingFilterProxy就是sevletFilter的实现类
org.springframework.web.filter.DelegatingFilterProxy#doFilter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { Filter delegateToUse = this.delegate; if (delegateToUse == null) { 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?"); } //<5>delegate初始化 delegateToUse = this.initDelegate(wac); } this.delegate = delegateToUse; } } // <6>最终是委托给delegate执行的 this.invokeDelegate(delegateToUse, request, response, filterChain); }
<5>
org.springframework.web.filter.DelegatingFilterProxy#initDelegate
protected Filter initDelegate(WebApplicationContext wac) throws ServletException { String targetBeanName = this.getTargetBeanName(); Assert.state(targetBeanName != null, "No target bean name set"); //就是我们的 springSecurityFilterChain Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class); if (this.isTargetFilterLifecycle()) { delegate.init(this.getFilterConfig()); } return delegate; }
<6>
org.springframework.web.filter.DelegatingFilterProxy#invokeDelegate
protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { delegate.doFilter(request, response, filterChain); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
2020-03-10 dubbo源码阅读-dubbo SPI实现原理(五)