这篇文章主要介绍“什么是SpringSecurity过滤器”,在日常操作中,相信很多人在什么是SpringSecurity过滤器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”什么是SpringSecurity过滤器”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
前置知识
我们知道Spring Security是通过Filter的方式来完成它的核心流程。但是:
-
Spring Security到底拥有哪些Filter?
-
这些Filter是如何注入容器?
-
我们如何自定义自己的Filter?
web.xml配置
前面我们已经介绍过了,最开始如果我们要配置Filter,一般是通过web.xml的方式:
<filter> <filter-name>deleFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>spring-bean-name</param-value> </init-param> </filter> <filter-mapping> <filter-name>deleFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
SpringBoot中添加Filter
在SpringBoot中可以通过@WebFilter和@ServletComponentScan注解,注入自定义的Filter。
@WebFilter(filterName = "myFilter",urlPatterns = "/*") public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { } @Override public void destroy() { } } @SpringBootApplication @ServletComponentScan(basePackages = "vip.mycollege.filter") public class StartApplication { public static void main(String[] args) { SpringApplication.run(StartApplication.class, args); } }
也可以通过FilterRegistrationBean的方式,注入自定义的Filter。
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean filterRegistrationBean(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new MyFilter()); bean.addUrlPatterns("/*"); return bean; } }
也可以通过DelegatingFilterProxyRegistrationBean的方式。
@Configuration public class FilterConfig { @Bean("proxyFilter") public Filter filter (){ return new Filter() { @Override public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { } @Override public void destroy() { } @Bean public DelegatingFilterProxyRegistrationBean delegatingFilterProxyRegistrationBean(){ DelegatingFilterProxyRegistrationBean bean = new DelegatingFilterProxyRegistrationBean("proxyFilter"); bean.addUrlPatterns("/*"); return bean; } }
DelegatingFilterProxyRegistrationBean和FilterRegistrationBean都继承了AbstractFilterRegistrationBean,从名字上看就知道是一个RegistrationBean,也就是说会在Servlet容器启动的时候被注入。
DelegatingFilterProxyRegistrationBean会在Servlet容器中注册一个DelegatingFilterProxy,用来代理Spring IoC容器中某个指定名称的Filter bean。
FilterChainProxy
SpringBoot有一个SecurityFilterAutoConfiguration的自动配置类,就会配置一个name为springSecurityFilterChain的DelegatingFilterProxyRegistrationBean,这个类的url-pattern默认为/*,也就是说会过滤所有的请求。
name是springSecurityFilterChain是一个什么鬼呢?
答案是:FilterChainProxy。
这个类是在HttpSecurityBeanDefinitionParser的registerFilterChainProxyIfNecessary方法中注册。
HttpSecurityBeanDefinitionParser也是一个BeanDefinitionParser,因此它会通过parse方法来构建Filter类。
整个流程现在就清晰了:
-
SpringBoot通过自动配置类搞了个DelegatingFilterProxyRegistrationBean
-
DelegatingFilterProxyRegistrationBean会在Servlet启动的时候注册一个DelegatingFilterProxy
-
DelegatingFilterProxy会默认会拦截所有的请求,然后交个一个别名为springSecurityFilterChain的FilterChainProxy
-
FilterChainProxy在持有一个SecurityFilterChain的list
-
SecurityFilterChain本身又持有一个Filter列表,可以通过match找出url匹配的Request交个filters处理
FilterChainProxy除了持有过滤器,默认内置了一个StrictHttpFirewall一个HTTP防火墙,它采用了严格模式,遇到任何可疑的请求,会通过抛出异常RequestRejectedException拒绝该请求。
现在我们知道了Spring Security如何收集利用Filter了。
但是,Spring Security到底背着我们弄了哪些Filter呢?
我只想说很多,要知道有哪些也很简单,在FilterChainProxy打一个断点,debug,看一下filterChains变量中的filters列表就能看到有哪些filter
默认情况下filterChains只有一个filte,就是DefaultSecurityFilterChain,看名字就知道这是一个SecurityFilterChain,他包含了一个Filter列表,默认有:
-
WebAsyncManagerIntegrationFilter:与处理异步请求映射的 WebAsyncManager 进行集成
-
SecurityContextPersistenceFilter: 请求前保存和请求后清除SecurityContextHolder中的安全上下文
-
HeaderWriterFilter:将头信息加入响应中
-
CsrfFilter:处理跨站请求伪造
-
LogoutFilter:处理登出
-
UsernamePasswordAuthenticationFilter:处理基于表单的登录
-
DefaultLoginPageGeneratingFilter:如果没有配置登录页,生成默认登录页
-
DefaultLogoutPageGeneratingFilter:如果没有登出页,生成默认登出页
-
BasicAuthenticationFilter:处理HTTP BASIC认证
-
RequestCacheAwareFilter:处理请求的缓存
-
SecurityContextHolderAwareRequestFilter:包装请求对象request
-
AnonymousAuthenticationFilter:检测SecurityContextHolder是否存在Authentication,如不存在提供一个匿名 Authentication
-
SessionManagementFilter:管理 session 的过滤器
-
ExceptionTranslationFilter:处理 AccessDeniedException 和 AuthenticationException 异常
-
FilterSecurityInterceptor: 权限校验相关
重要Filter
UsernamePasswordAuthenticationFilter
UsernamePasswordAuthenticationFilter本身没啥好说的,它就是一个Filter,但是因为它用得多,所以说一下。
Filter肯定先看doFilter方法,UsernamePasswordAuthenticationFilter的主要认证逻辑在attemptAuthentication:
@Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (this.postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } String username = obtainUsername(request); username = (username != null) ? username : ""; username = username.trim(); String password = obtainPassword(request); password = (password != null) ? password : ""; UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); }
很简单,就是从request中获取username和password的字段,封装成UsernamePasswordAuthenticationToken,然后扔给AuthenticationManager去执行认证,当然,最终认证逻辑肯定是像DaoAuthenticationProvider 这样的AuthenticationProvider执行。
FilterSecurityInterceptor
FilterSecurityInterceptor主要是用来做权限校验的,具体的鉴权逻辑主要在AbstractSecurityInterceptor中。
FilterSecurityInterceptor也是一个Filter,所以,还是先看doFilter方法,调用了invoke:
public void invoke(FilterInvocation filterInvocation) throws IOException, ServletException { //一次请求中避免重复检查 if (isApplied(filterInvocation) && this.observeOncePerRequest) { filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse()); return; } // 第一次调用,先设置标记,避免重复调用 if (filterInvocation.getRequest() != null && this.observeOncePerRequest) { filterInvocation.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE); } // 业务逻辑调用之前,执行检查鉴权操作主要就是在这里面完成 InterceptorStatusToken token = super.beforeInvocation(filterInvocation); try { // 执行具体的业务逻辑 filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse()); } finally { super.finallyInvocation(token); } // 业务逻辑调用之后,主要是处理返回结果 super.afterInvocation(token, null); }
FilterInvocation就是FilterInvocation、ServletResponse、FilterChain的简单封装。
我们看到整个invoke的逻辑非常清晰,很像AOP的around结构。
ExceptionTranslationFilter
ExceptionTranslationFilter的逻辑有点奇怪,它主要是为了处理 AccessDeniedException 和 AuthenticationException 异常。但是并不是处理它前面产生的异常,而是它后面的Filter产生的异常,因为它前面Filter如果异常了根本到不了它这里。
它后面,默认就只有FilterSecurityInterceptor了,主要会产生AccessDeniedException授权异常,AuthenticationException是因为有一个再认证的过程。
过滤器
-
WebAsyncManagerIntegrationFilter
-
SecurityContextPersistenceFilter
-
ChannelProcessingFilter
-
ConcurrentSessionFilter
-
HeaderWriterFilter
-
CorsFilter
-
CsrfFilter
-
LogoutFilter
-
OAuth3AuthorizationRequestRedirectFilter
-
Saml2WebSsoAuthenticationRequestFilter
-
X509AuthenticationFilter
-
AbstractPreAuthenticatedProcessingFilter
-
CasAuthenticationFilter
-
OAuth3LoginAuthenticationFilter
-
Saml2WebSsoAuthenticationFilter
-
UsernamePasswordAuthenticationFilter
-
ConcurrentSessionFilter
-
OpenIDAuthenticationFilter
-
DefaultLoginPageGeneratingFilter
-
DefaultLogoutPageGeneratingFilter
-
DigestAuthenticationFilter
-
BearerTokenAuthenticationFilter
-
BasicAuthenticationFilter
-
RequestCacheAwareFilter
-
SecurityContextHolderAwareRequestFilter
-
JaasApiIntegrationFilter
-
RememberMeAuthenticationFilter
-
AnonymousAuthenticationFilter
-
OAuth3AuthorizationCodeGrantFilter
-
SessionManagementFilter
-
ExceptionTranslationFilter
-
SwitchUserFilter
-
FilterSecurityInterceptor
到此,关于“什么是SpringSecurity过滤器”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注本站网站,小编会继续努力为大家带来更多实用的文章!