以上就是给各位分享SpringSecurityFilterOrdering,同时本文还将给你拓展HowSpringSecurityFilterChainworks、JavaSpringSecurity
以上就是给各位分享Spring Security Filter Ordering,同时本文还将给你拓展How Spring Security Filter Chain works、Java Spring Security @PostFilter 性能、java – Spring:异常启动过滤器springSecurityFilterChain、Java-Security (二):如何初始化 springSecurityFilterChain(FilterChainProxy)等相关知识,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:- Spring Security Filter Ordering
- How Spring Security Filter Chain works
- Java Spring Security @PostFilter 性能
- java – Spring:异常启动过滤器springSecurityFilterChain
- Java-Security (二):如何初始化 springSecurityFilterChain(FilterChainProxy)
Spring Security Filter Ordering
The order that filters are defined in the chain is very important. Irrespective of which filters you are actually using, the order should be as follows:
ChannelProcessingFilter
, because it might need to redirect to a different protocolSecurityContextPersistenceFilter
, so aSecurityContext
can be set up in theSecurityContextHolder
at the beginning of a web request, and any changes to theSecurityContext
can be copied to theHttpSession
when the web request ends (ready for use with the next web request)ConcurrentSessionFilter
, because it uses theSecurityContextHolder
functionality and needs to update theSessionRegistry
to reflect ongoing requests from the principalAuthentication processing mechanisms -
UsernamePasswordAuthenticationFilter
,CasAuthenticationFilter
,BasicAuthenticationFilter
etc - so that theSecurityContextHolder
can be modified to contain a validAuthentication
request tokenThe
SecurityContextHolderAwareRequestFilter
, if you are using it to install a Spring Security awareHttpServletRequestWrapper
into your servlet containerThe
JaasApiIntegrationFilter
, if aJaasAuthenticationToken
is in theSecurityContextHolder
this will process theFilterChain
as theSubject
in theJaasAuthenticationToken
RememberMeAuthenticationFilter
, so that if no earlier authentication processing mechanism updated theSecurityContextHolder
, and the request presents a cookie that enables remember-me services to take place, a suitable rememberedAuthentication
object will be put thereAnonymousAuthenticationFilter
, so that if no earlier authentication processing mechanism updated theSecurityContextHolder
, an anonymousAuthentication
object will be put thereExceptionTranslationFilter
, to catch any Spring Security exceptions so that either an HTTP error response can be returned or an appropriateAuthenticationEntryPoint
can be launchedFilterSecurityInterceptor
, to protect web URIs and raise exceptions when access is denied
How Spring Security Filter Chain works
我意识到Spring安全性是建立在过滤器链上的,该过滤器将拦截请求,检测(不存在)身份验证,重定向到身份验证入口点或将请求传递给授权服务,并最终让请求到达servlet或引发安全异常(未经身份验证或未经授权)。DelegatingFitlerProxy将这些过滤器粘合在一起。为了执行任务,这些过滤器访问服务,例如UserDetailsService和AuthenticationManager。
链中的关键过滤器为(按顺序)
- SecurityContextPersistenceFilter(从JSESSIONID恢复身份验证)
- UsernamePasswordAuthenticationFilter(执行身份验证)
- ExceptionTranslationFilter(从FilterSecurityInterceptor捕获安全异常)
- FilterSecurityInterceptor(可能会抛出身份验证和授权异常)
我很困惑如何使用这些过滤器。是否是在Spring提供的表单登录中,UsernamePasswordAuthenticationFilter仅用于/ login,而后面的过滤器不使用?表单登录名称空间元素是否自动配置这些过滤器?是否每个请求(无论是否经过身份验证)都到达非登录URL的FilterSecurityInterceptor?
如果我想使用从登录名检索到的JWT-token保护我的REST API ,该怎么办?我必须配置两个名称空间配置http标签,对吗?一个用于/登录使用UsernamePasswordAuthenticationFilter
,而另一个用于REST的URL,自定义JwtAuthenticationFilter
。
配置两个http元素会创建两个元素springSecurityFitlerChains
吗?是UsernamePasswordAuthenticationFilter
默认是关闭的,直到我宣布form-login
?如何SecurityContextPersistenceFilter
用Authentication
将从现有JWT-token
而不是从中获得的过滤器替换JSESSIONID
?
答案1
小编典典Spring安全过滤器链是一个非常复杂且灵活的引擎。
链中的关键过滤器为(按顺序)
- SecurityContextPersistenceFilter(从JSESSIONID恢复身份验证)
- UsernamePasswordAuthenticationFilter(执行身份验证)
- ExceptionTranslationFilter(从FilterSecurityInterceptor捕获安全异常)
- FilterSecurityInterceptor(可能会抛出身份验证和授权异常)
查看当前的稳定发行版4.2.1文档的13.3节“ 过滤器订购”,你可以看到整个过滤器链的过滤器组织:
13.3过滤器订购
链中定义过滤器的顺序非常重要。不管你实际使用哪个过滤器,其顺序都应如下:
ChannelProcessingFilter,因为它可能需要重定向到其他协议
SecurityContextPersistenceFilter,因此可以在Web请求开始时在SecurityContextHolder中设置SecurityContext,并且在Web请求结束时(可以与下一个Web请求一起使用)可以将对SecurityContext的任何更改复制到HttpSession中。
ConcurrentSessionFilter,因为它使用SecurityContextHolder功能,并且需要更新SessionRegistry以反映来自主体的持续请求
认证处理机制- UsernamePasswordAuthenticationFilter,CasAuthenticationFilter, BasicAuthenticationFilter一样等-这样SecurityContextHolder可被修饰以包含有效的认证请求令牌
该SecurityContextHolderAwareRequestFilter,如果你使用它来安装一个Spring安全意识了HttpServletRequestWrapper到你的servlet容器
该JaasApiIntegrationFilter,如果JaasAuthenticationToken在SecurityContextHolder中,这将处理FilterChain作为JaasAuthenticationToken主题
RememberMeAuthenticationFilter,因此,如果没有早期的身份验证处理机制更新SecurityContextHolder,并且该请求显示一个cookie来启用“记住我”服务,则会在此处放置一个合适的记住的Authentication对象
AnonymousAuthenticationFilter,因此,如果没有早期的身份验证处理机制更新SecurityContextHolder,则将在此处放置一个匿名Authentication对象
ExceptionTranslationFilter,以捕获任何Spring Security异常,以便可以返回HTTP错误响应或可以启动适当的AuthenticationEntryPoint
FilterSecurityInterceptor,用于保护Web URI并在拒绝访问时引发异常
现在,我将一一解答你的问题:
我很困惑如何使用这些过滤器。是不是在spring提供的表单登录中,UsernamePasswordAuthenticationFilter仅用于/ login,而后一个过滤器却没有?表单登录名称空间元素是否自动配置这些过滤器?是否每个请求(无论是否经过身份验证)都到达非登录URL的FilterSecurityInterceptor?
一旦配置了一个<security-http>
部分,对于每个部分,你至少必须提供一种身份验证机制。这必须是与我刚刚参考的Spring Security文档中13.3 Filter Ordering部分中的第4组匹配的过滤器之一。
这是可以配置的最低有效security:http元素:
<security:http authentication-manager-ref="mainAuthenticationManager" entry-point-ref="serviceAccessDeniedHandler"> <security:intercept-url pattern="/sectest/zone1/**" access="hasRole(''ROLE_ADMIN'')"/></security:http>
只需执行以下操作,即可在过滤器链代理中配置以下过滤器:
{ "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter", "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter", "3": "org.springframework.security.web.header.HeaderWriterFilter", "4": "org.springframework.security.web.csrf.CsrfFilter", "5": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter", "6": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter", "7": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter", "8": "org.springframework.security.web.session.SessionManagementFilter", "9": "org.springframework.security.web.access.ExceptionTranslationFilter", "10": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor" }
注意:我通过创建一个简单的RestController来获得它们,该控制器@Autowires FilterChainProxy并返回其内容:
@Autowired private FilterChainProxy filterChainProxy; @Override @RequestMapping("/filterChain") public @ResponseBody Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){ return this.getSecurityFilterChainProxy(); } public Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){ Map<Integer, Map<Integer, String>> filterChains= new HashMap<Integer, Map<Integer, String>>(); int i = 1; for(SecurityFilterChain secfc : this.filterChainProxy.getFilterChains()){ //filters.put(i++, secfc.getClass().getName()); Map<Integer, String> filters = new HashMap<Integer, String>(); int j = 1; for(Filter filter : secfc.getFilters()){ filters.put(j++, filter.getClass().getName()); } filterChains.put(i++, filters); } return filterChains; }
在这里,我们可以看到仅通过声明<security:http>
一个最低配置元素就包括了所有默认过滤器,但它们都不是Authentication类型的(13.3 Filter Ordering部分中的第4组)。因此,这实际上意味着仅通过声明security:http
元素,就可以自动配置SecurityContextPersistenceFilter,ExceptionTranslationFilter和FilterSecurityInterceptor。
实际上,应该配置一种身份验证处理机制,甚至安全性名称空间bean也要为此处理声明,在启动过程中引发错误,但是可以绕过它,在其中添加entry-point-ref属性。<http:security>
如果我<form-login>
在配置中添加基本设置,则可以这样:
<security:http authentication-manager-ref="mainAuthenticationManager"> <security:intercept-url pattern="/sectest/zone1/**" access="hasRole(''ROLE_ADMIN'')"/> <security:form-login /></security:http>
现在,filterChain将像这样:
{ "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter", "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter", "3": "org.springframework.security.web.header.HeaderWriterFilter", "4": "org.springframework.security.web.csrf.CsrfFilter", "5": "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter", "6": "org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter", "7": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter", "8": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter", "9": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter", "10": "org.springframework.security.web.session.SessionManagementFilter", "11": "org.springframework.security.web.access.ExceptionTranslationFilter", "12": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor" }
现在,这两个过滤器org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter和org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter在FilterChainProxy中创建和配置。
因此,现在的问题是:
是不是在spring提供的表单登录中,UsernamePasswordAuthenticationFilter仅用于/ login,而后一个过滤器却没有?
是的,它用于尝试完成登录处理机制,以防请求与UsernamePasswordAuthenticationFilter URL匹配。可以配置甚至更改此url的行为以匹配每个请求。
你也可能在同一FilterchainProxy中配置了多个身份验证处理机制(例如HttpBasic,CAS等)。
表单登录名称空间元素是否自动配置这些过滤器?
不,form-login元素配置UsernamePasswordAUthenticationFilter,并且如果你不提供登录页面网址,它还会配置org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter,以简单的自动生成的登录名结尾页。
默认情况下,仅通过创建<security:http>
不带security:"none"
属性的元素即可自动配置其他过滤器。
是否每个请求(无论是否经过身份验证)都到达非登录URL的FilterSecurityInterceptor
?
每个请求都应该到达它,因为它是一个元素,它负责处理请求是否有权访问所请求的url。但是,之前处理过的某些过滤器可能会停止过滤链处理,只是不调用FilterChain.doFilter(request, response);
。例如,如果请求没有csrf参数,则CSRF筛选器可能会停止筛选器链处理。
如果我想用从登录名中检索到的JWT令牌保护我的REST API,该怎么办?我必须配置两个名称空间配置http标记,对吗?另一个用于/ login UsernamePasswordAuthenticationFilter
,另一个用于REST URL,带有custom JwtAuthenticationFilter。
不,你没有被迫这样做。你可以在同一个http元素中声明UsernamePasswordAuthenticationFilter
和JwtAuthenticationFilter
,但这取决于每个过滤器的具体行为。两种方法都是可行的,最后选择哪种方法取决于自己的偏好。
配置两个http元素会创建两个springSecurityFitlerChains吗?
是的,这是真的
在我声明表单登录之前,UsernamePasswordAuthenticationFilter是否默认关闭?
是的,你可以在我发布的每个配置中引发的过滤器中看到它
如何用一个替换SecurityContextPersistenceFilter,它将从现有的JWT令牌而不是JSESSIONID获得身份验证?
你可以避开SecurityContextPersistenceFilter,只是配置会话策略在<http:element>
。只需这样配置:
<security:http create-session="stateless" >
或者,在这种情况下,你可以用另一个过滤器覆盖它,方法是在
<security:http ...> <security:custom-filter ref="myCustomFilter" position="SECURITY_CONTEXT_FILTER"/> </security:http><beans:bean id="myCustomFilter"/>
编辑:
一个有关“你可能在同一个FilterchainProxy中配置多个身份验证处理机制”的问题。如果声明多个(Spring实现)身份验证过滤器,后者会覆盖由第一个身份验证执行的身份验证吗?这与拥有多个身份验证提供者有何关系?
最终,这取决于每个过滤器本身的实现,但事实上,后一个身份验证过滤器至少能够覆盖由先前过滤器最终进行的任何先前身份验证。
但这不一定会发生。我在安全的REST服务中有一些生产案例,其中我使用一种授权令牌,可以将其作为Http标头或在请求正文中提供。因此,我配置了两个过滤器来恢复该令牌,一种情况是从Http标头中恢复,另一种是从自己的其余请求的请求正文中恢复。的事实是,如果一个http请求同时提供身份验证令牌作为Http标头和请求主体内部,则两个过滤器都将尝试执行将身份验证令牌委派给管理器的身份验证机制,但是只需检查请求是否为仅在doFilter()每个过滤器方法开始时就已通过身份验证。
具有多个身份验证过滤器与具有多个身份验证提供程序有关,但不要强行使用。在我之前公开的情况下,我有两个身份验证过滤器,但我只有一个身份验证提供程序,因为两个过滤器都创建相同类型的身份验证对象,因此在两种情况下,身份验证管理器都将其委托给相同的提供程序。
与此相反,我也有一种情况,我只发布一个UsernamePasswordAuthenticationFilter,但是用户凭据都可以包含在DB或LDAP中,因此我有两个UsernamePasswordAuthenticationToken支持提供者,而AuthenticationManager将来自过滤器的任何身份验证尝试委托给提供者安全地验证凭据。
因此,我认为很明显,身份验证筛选器的数量不能确定身份验证提供程序的数量,也不能由提供者的数量确定筛选器的数量。
此外,文档指出SecurityContextPersistenceFilter负责清理SecurityContext,这对线程池很重要。如果我省略它或提供自定义实现,则必须手动实现清理,对吗?定制链时还有更多类似的陷阱吗?
在此之前,我没有仔细研究过此过滤器,但是在你问完最后一个问题之后,我一直在检查它的实现,并且像通常在Spring中一样,几乎所有东西都可以配置,扩展或覆盖。
该SecurityContextPersistenceFilter
在代表SecurityContextRepository
执行搜索SecurityContext中。默认情况下,使用HttpSessionSecurityContextRepository
,但是可以使用过滤器的构造函数之一进行更改。因此,最好编写一个满足你需要的SecurityContextRepository并仅在SecurityContextPersistenceFilter中对其进行配置,并相信它已被证明的行为,而不是从头开始。
Java Spring Security @PostFilter 性能
如何解决Java Spring Security @PostFilter 性能?
我的 Java Spring 应用程序使用 ACL,有一个服务方法来检索与给定用户对应的所有对象:
@Override
@PostFilter("hasPermission(filterObject,''READ'') or hasPermission(filterObject,''ADMINISTRATION'')")
public List<SomeClass> findAll() {
return SomeClassRepository.findAll();
}
不幸的是,在数据库中有很多对象的情况下,此方法需要太多时间才能完成(超过 1 秒)。可能是因为它会先从数据库中取出所有的对象,然后在内存中一一过滤。如何在不失去 Spring ACL 的好处的情况下对此进行优化?
编辑:我现在想出的解决方案是为 acl_sid
和 acl_entry
存储库创建存储库,并通过这些存储库获取感兴趣对象的 ID。与上述方法相比,这使我的执行时间提高了 10 倍。新代码如下所示:
@Override
@PostFilter("hasPermission(filterObject,''ADMINISTRATION'')")
public List<SomeClass> findAll() {
List<SomeClass> result = new ArrayList<SomeClass>();
Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
AclSid sid = aclSidRepository.findBySid(Long.toString(userId));
List<AclEntry> aclEntries = aclEntryRepository.findBySid(sid);
for (AclEntry aclEntry : aclEntries) {
AclObjectIdentity aclObjectIdentity = aclEntry.getAclObjectIdentity();
AclClass aclClass = aclObjectIdentity.getobjectIdClass();
if (aclClass.getClassName().equals("com.company.app.entity.someClass")) {
Optional<SomeClass> SomeClass = SomeClassRepository
.findById(aclObjectIdentity.getobjectIdIdentity());
if (SomeClass.isPresent()) {
result.add(SomeClass.get());
}
}
}
return result;
}
解决方法
由于 Spring 过滤内存中的信息,性能将取决于实际结果的数量:如果它们的数量很大,恐怕只在过滤信息之前缓存您的存储库结果可能是一个合适的解决方案。
为了处理这个问题,可以在数据库层面对结果进行过滤。我想到了两种方法:
- 要么使用
Specification
,并在数据库级别过滤结果,同时考虑 Spring SecuritySecurityContext
公开的主体的信息,并包括必要的过滤器Predicates
,以便限制返回的信息。 - 或者,如果您使用的是 Hibernate,请再次使用 entity filters,根据 Spring Security 公开的主体信息,应用必要的数据限制。请参阅 this related SO question,其中提供了有关解决方案的详细信息。
@OsamaAbdulRehman 在他的评论中提出的解决方案看起来也很有趣,尽管老实说我从未测试过它。
java – Spring:异常启动过滤器springSecurityFilterChain
当我启动服务器我得到这个错误:
SEVERE: Exception starting filter springSecurityFilterChain
org.springframework.beans.factory.NoSuchBeanDeFinitionException: Nobean named ‘springSecurityFilterChain’ is defined at
org.springframework.beans.factory.support.DefaultListablebeanfactory.getBeanDeFinition(DefaultListablebeanfactory.java:553)
at
org.springframework.beans.factory.support.Abstractbeanfactory.getMergedLocalBeanDeFinition(Abstractbeanfactory.java:1095)
at
org.springframework.beans.factory.support.Abstractbeanfactory.doGetBean(Abstractbeanfactory.java:277)
at
org.springframework.beans.factory.support.Abstractbeanfactory.getBean(Abstractbeanfactory.java:197)
at
org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1102)
这是我的配置文件:
web.xml
<display-name>myTest</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> <context-param> <param-name>defaultHtmlEscape</param-name> <param-value>true</param-value> </context-param> <!-- Creates the Spring Container shared by all Servlets and Filters --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> </listener> <!-- Processes application requests --> <servlet> <servlet-name>springTest</servlet-name> <servlet-class>org.springframework.web.servlet.dispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springTest</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
这是root-context.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd"> <context:annotation-config /> <context:component-scan base-package="com.myTest.db.entities"/> <context:component-scan base-package="com.myTest.services"/> <context:component-scan base-package="com.myTest.web"/> <import resource="mvc-config.xml" />
这是
security-config.xml
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <!-- Additional filter chain for normal users,matching all other requests --> <http pattern="/resources/**" security="none" /> <http use-expressions="true"> <intercept-url pattern="/login" access='isAnonymous()' requires-channel='http' /> <intercept-url pattern="/" access='permitAll' requires-channel='http'/> <intercept-url pattern='/**' access='isAuthenticated()' requires-channel='http'/> <form-login login-page="/login" authentication-failure-url="/login" default-target-url="/welcome" /> <access-denied-handler ref="accessDeniedHandler" /> <logout logout-url="/logout" logout-success-url="/" /> </http> <beans:bean id="accessDeniedHandler"https://www.jb51.cc/tag/ecurity/" target="_blank">ecurity.web.access.AccessDeniedHandlerImpl"> <beans:property name="errorPage" value="/WEB-INF/pages/error.jsp"/> </beans:bean> <authentication-manager> <authentication-provider user-service-ref="userAuthenticationService"> <password-encoder hash="sha-256"> <salt-source user-property="salt" /> </password-encoder> </authentication-provider> </authentication-manager> <!-- User Detail Services --> <beans:bean id="userAuthenticationService"https://www.jb51.cc/tag/ecurity/" target="_blank">ecurity.AuthenticationServiceImpl" />
有任何想法吗?
解决方法
你可能需要这样的东西:
<param-value>/WEB-INF/spring/security-config.xml</param-value>
之后
<param-value>/WEB-INF/spring/root-context.xml</param-value>
在web.xml中
Java-Security (二):如何初始化 springSecurityFilterChain(FilterChainProxy)
上一篇文章中,接触了 Spring Security 并写了一个简单的实例,初次接触毕竟我们对它还不是特别熟悉。我比较好奇的问题包含两处:
1)配置在 web.xml 配置的 springSecurityFilterChain 是如何被加载?
2)配置在 applicationContext-security.xml 中的标签 csrf、form-login、logout 是如何被解析的呢?
1)配置在 web.xml 配置的 springSecurityFilterChain 是如何被加载?
springmvc+spring security 项目中 web.xml 配置了 springSecurityFilterChain
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<!-- 默认是false -->
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
org.springframework.web.filter.DelegatingFilterProxy 只是和其他 filter 一样,是一个 javax.servlet.Filter,它将在 web servlet 系统启动时:先调用 listener (pre)->filter (pre doFilter)->servlet ([spring mvc] DispatcherServlet)->filter (after doFilter)->listener (after )
因此项目启动时,会执行 DelegatingFilterProxy#doFilter 方法
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Lazily initialize the delegate if necessary.
Filter delegateToUse = this.delegate;
if (delegateToUse == null) {
synchronized (this.delegateMonitor) {
delegateToUse = this.delegate;
if (delegateToUse == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: " +
"no ContextLoaderListener or DispatcherServlet registered?");
}
delegateToUse = initDelegate(wac);
}
this.delegate = delegateToUse;
}
}
// Let the delegate perform the actual doFilter operation.
invokeDelegate(delegateToUse, request, response, filterChain);
}
上边 filter 执行主要负责两个事情:
1)执行 initDelegate (wac) 方法,初始化 delegate 对象
因为 DelegatingFilterProxy 类继承于抽象类(springframework 的)GenericFilterBean,会在初始化 bean 时,调用 DelegatingFilterProxy#initFilterBean ()
GenericFilterBean 的定义:
public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware,
EnvironmentCapable, ServletContextAware, InitializingBean, DisposableBean {
// ...
@Override
public void afterPropertiesSet() throws ServletException {
initFilterBean();
}
// ...
protected void initFilterBean() throws ServletException {
}
// ...
}
因为 GenericFilterBean 实现 InitializingBean 接口,因此项目启动时,spring 容器加载 bean 后,会执行 afterPropertiesSet () 方法,之后会调用 initFilterBean () 方法。
DelegatingFilterProxy#initFilterBean () 的定义:
public class DelegatingFilterProxy extends GenericFilterBean {
// ...
@Nullable
private volatile Filter delegate;
// ...
@Override
protected void initFilterBean() throws ServletException {
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
// If no target bean name specified, use filter name.
if (this.targetBeanName == null) {
this.targetBeanName = getFilterName();
}
// Fetch Spring root application context and initialize the delegate early,
// if possible. If the root application context will be started after this
// filter proxy, we''ll have to resort to lazy initialization.
WebApplicationContext wac = findWebApplicationContext();
if (wac != null) {
this.delegate = initDelegate(wac);
}
}
}
}
// ...
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
String targetBeanName = getTargetBeanName();
Assert.state(targetBeanName != null, "No target bean name set");
Filter delegate = wac.getBean(targetBeanName, Filter.class);
if (isTargetFilterLifecycle()) {
delegate.init(getFilterConfig());
}
return delegate;
}
// ...
}
当然,无论 targetFilterLifecycle 是 true 还是 false,都不会影响 springSecurityFilterChain 的初始化(无论 true 还是 false,以下截图的结果都一样)。
从上图我们能得出的结论:
1)上边 targetBeanName 是 springSecurityFilterChain,通过调用 wac.getBean (targetBeanName, Filter.class); 从 spring 容器中获取到对象的类:org.springframework.security.web.FilterChainProxy;
2)‘org.springframework.security.web.FilterChainProxy#filterChains’与‘applicationContext-shiro.xml 中的 <http/> 标签对应’;
3)‘filterChains 的个数’与‘applicationContext-shiro.xml 中的 <http/> 标签个数一致’,也就是说:在 applicationContext-shiro.xml 中配置了几个 < http/> 标签,那么,‘org.springframework.security.web.FilterChainProxy#filterChains’就对应几个 ‘DefaultSecurityFilterChain’ 对象元素。
4)这个 springSecurityFilterChain 的 bean 是如何初始化,和什么时候放入 spring 容器的呢?在 ContextLoaderListener 加载 applicationContext-security.xml 时,解析配置文件时将 springSecurityFilterChain 初始化放入容器的,这个问题后边会详细介绍。
2)执行 invokeDelegate (...) 方法
实际上就是执行 FilterChainProxy#doFilter (...) 方法
protected void invokeDelegate(
Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
delegate.doFilter(request, response, filterChain);
}
2)配置在 applicationContext-security.xml 中的标签 csrf、form-login、logout 是如何被解析的呢?
applicationContext-security.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
<!--
从Spring Security 3.1开始,可以使用多个http元素为不同的请求模式定义单独的安全过滤器链配置。
-->
<security:http pattern="/css/**" security="none"/>
<security:http auto-config="true" use-expressions="false">
<security:csrf disabled="false"/>
<security:intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:intercept-url pattern="/index" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:intercept-url pattern="/**" access="ROLE_USER"/>
<security:form-login default-target-url="/index" />
<security:logout delete-cookies="JSESSIONID" logout-success-url="/login" logout-url="/logout" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<!-- Password is prefixed with {noop} to indicate to DelegatingPasswordEncoder that
NoOpPasswordEncoder should be used. This is not safe for production, but makes reading
in samples easier. Normally passwords should be hashed using BCrypt
-->
<security:user name="admin" password="{noop}adminpwd" authorities="ROLE_USER, ROLE_ADMIN"/>
<security:user name="user" password="{noop}userpwd" authorities="ROLE_USER"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
上边的配置文件是比较简单的 spring security 配置文件了,在 springmvc (web.xml 非注解方式)+spring security 项目中,我们需要清楚一件事:就是 web.xml 中配置的内容的执行先后顺序。
web.xml 配置内容如下:


<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<welcome-file-list>
<welcome-file>/index</welcome-file>
</welcome-file-list>
<!--加载dao/service/一些共享组件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext-base.xml,
classpath:applicationContext-security.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<!-- 默认是false -->
<param-value>false</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
<init-param>
<param-name>multipartResolverBeanName</param-name>
<param-value>multipartResolver</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
<init-param>
<param-name>methodParam</param-name>
<param-value>_method</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--加载springmvc controller viewsolver 等-->
<servlet>
<servlet-name>spring-security-01</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-security-01-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-security-01</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
配置文件中指定的
有两个 spring application context 初始化的地方:
1)ContextLoaderListener 加载 applicationContext-base.xml、applicationContext-security.xml,初始化 parent application context;
2)DispatcherServlet 加载 spring-security-01-servlet.xml,初始化 child application context。
注意:
1)web.xml 中配置内容加载顺序:
-》listener[pre] -》filter[pre] -》springmvc 内部处理 -》filter[after] -》listener[after]; 2)ContextLoaderListener 加载 applicationContext-security.xml 时,需要先根据标签解析器(SecurityNamespaceHandler)解析 xml 中配置 http、csrf、form-login、logout 等标签:
在 spring-security 项目 config 模块的 src/main/resources/META-INF/spring.handlers 文件中配合这这样一行代码:
http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler
从这里可以看出来 spring security 的标签解析器是 org.springframework.security.config.SecurityNamespaceHandler 来处理。
SecurityNamespaceHandler 该类接口是:NamespaceHandler
public interface NamespaceHandler {
void init();
@Nullable
BeanDefinition parse(Element element, ParserContext parserContext);
@Nullable
BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);
}
该接口定义了三个方法:
init 方法:用于自定义标签的初始化
parse 方法:用于解析标签
decorate 方法:用于装饰。
SecurityNamespaceHandler 类
在 spring-security 项目中,加载 applicationContext-security.xml 中处理 xml 中配置 http、csrf、form-login、logout 等(所有 xml 配置 security 标签,具体所有标签定义:参考 org.springframework.security.config.Elements.java),在处理 xml 这些标签的最终目的是:
解析 xml 中配置的 bean,并将它们加载到 spring-framework 上下文,供 spring-security、spring-mvc 项目使用。
其中在 org.springframework.security.config.SecurityNamespaceHandler#init 方法完成了标签解析类注册的工作:
public void init() {
loadParsers();
}
private void loadParsers() {
// Parsers
parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
parsers.put(Elements.LDAP_USER_SERVICE, new LdapUserServiceBeanDefinitionParser());
parsers.put(Elements.USER_SERVICE, new UserServiceBeanDefinitionParser());
parsers.put(Elements.JDBC_USER_SERVICE, new JdbcUserServiceBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
parsers.put(Elements.METHOD_SECURITY_METADATA_SOURCE, new MethodSecurityMetadataSourceBeanDefinitionParser());
// Only load the web-namespace parsers if the web classes are available
if (ClassUtils.isPresent(FILTER_CHAIN_PROXY_CLASSNAME, getClass().getClassLoader())) {
parsers.put(Elements.DEBUG, new DebugBeanDefinitionParser());
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
}
if (ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {
parsers.put(Elements.WEBSOCKET_MESSAGE_BROKER, new WebSocketMessageBrokerSecurityBeanDefinitionParser());
}
}
从上边代码可以看出:
<http/> 标签的解析类注册代码为:parsers.put (Elements.HTTP, new HttpSecurityBeanDefinitionParser ());
<authentication-manager/> 标签的解析类注册代码为:parsers.put (Elements.AUTHENTICATION_MANAGER,new AuthenticationManagerBeanDefinitionParser ());
<authentication-provider/> 标签的解析类注册代码为:parsers.put (Elements.AUTHENTICATION_PROVIDER,new AuthenticationProviderBeanDefinitionParser ())。
HttpSecurityBeanDefinitionParser 类
HttpSecurityBeanDefinitionParser 的 parse 方法代码:
@Override
public BeanDefinition parse(Element element, ParserContext pc) {
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(
element.getTagName(), pc.extractSource(element));
pc.pushContainingComponent(compositeDef);
registerFilterChainProxyIfNecessary(pc, pc.extractSource(element));
// Obtain the filter chains and add the new chain to it
// 这里FILTER_CHAINS字符串为:org.springframework.security.filterChains
BeanDefinition listFactoryBean = pc.getRegistry().getBeanDefinition(BeanIds.FILTER_CHAINS);
// 其中sourceList是从spring-security.xsd 文件中读取的:
List<BeanReference> filterChains = (List<BeanReference>) listFactoryBean.getPropertyValues().getPropertyValue("sourceList").getValue();
filterChains.add(createFilterChain(element, pc));
pc.popAndRegisterContainingComponent();
return null;
}
其中 registerFilterChainProxyIfNecessary () 实现代码如下:
static void registerFilterChainProxyIfNecessary(ParserContext pc, Object source) {
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
return;
}
// Not already registered, so register the list of filter chains and the
// FilterChainProxy
BeanDefinition listFactoryBean = new RootBeanDefinition(ListFactoryBean.class);
listFactoryBean.getPropertyValues().add("sourceList", new ManagedList());
pc.registerBeanComponent(new BeanComponentDefinition(listFactoryBean, BeanIds.FILTER_CHAINS));
BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
fcpBldr.getRawBeanDefinition().setSource(source);
fcpBldr.addConstructorArgReference(BeanIds.FILTER_CHAINS);
fcpBldr.addPropertyValue("filterChainValidator", new RootBeanDefinition(DefaultFilterChainValidator.class));
BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
}
备注:
1)FILTER_CHAIN_PROXY 就是 org.springframework.security.filterChainProxy
2)SPRING_SECURITY_FILTER_CHAIN 就是 springSecurityFilterChain
3)这段代码就是注册 bean 定义 FilterChainProxy 注册的地方,将 bean 名称定义为:org.springframework.security.filterChainProxy 和 springSecurityChainFilter(别名)
其中,createFilterChain 方法
/**
* Creates the {@code SecurityFilterChain} bean from an <http> element.
*/
private BeanReference createFilterChain(Element element, ParserContext pc) {
boolean secured = !OPT_SECURITY_NONE.equals(element.getAttribute(ATT_SECURED));
if (!secured) {
if (!StringUtils.hasText(element.getAttribute(ATT_PATH_PATTERN))
&& !StringUtils.hasText(ATT_REQUEST_MATCHER_REF)) {
pc.getReaderContext().error(
"The ''" + ATT_SECURED
+ "'' attribute must be used in combination with"
+ " the ''" + ATT_PATH_PATTERN + "'' or ''"
+ ATT_REQUEST_MATCHER_REF + "'' attributes.",
pc.extractSource(element));
}
for (int n = 0; n < element.getChildNodes().getLength(); n++) {
if (element.getChildNodes().item(n) instanceof Element) {
pc.getReaderContext().error(
"If you are using <http> to define an unsecured pattern, "
+ "it cannot contain child elements.",
pc.extractSource(element));
}
}
return createSecurityFilterChainBean(element, pc, Collections.emptyList());
}
final BeanReference portMapper = createPortMapper(element, pc);
final BeanReference portResolver = createPortResolver(portMapper, pc);
ManagedList<BeanReference> authenticationProviders = new ManagedList<>();
BeanReference authenticationManager = createAuthenticationManager(element, pc,
authenticationProviders);
boolean forceAutoConfig = isDefaultHttpConfig(element);
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element,
forceAutoConfig, pc, portMapper, portResolver, authenticationManager);
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element,
forceAutoConfig, pc, httpBldr.getSessionCreationPolicy(),
httpBldr.getRequestCache(), authenticationManager,
httpBldr.getSessionStrategy(), portMapper, portResolver,
httpBldr.getCsrfLogoutHandler());
httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
httpBldr.setEntryPoint(authBldr.getEntryPointBean());
httpBldr.setAccessDeniedHandler(authBldr.getAccessDeniedHandlerBean());
authenticationProviders.addAll(authBldr.getProviders());
List<OrderDecorator> unorderedFilterChain = new ArrayList<>();
unorderedFilterChain.addAll(httpBldr.getFilters());
unorderedFilterChain.addAll(authBldr.getFilters());
unorderedFilterChain.addAll(buildCustomFilterList(element, pc));
unorderedFilterChain.sort(new OrderComparator());
checkFilterChainOrder(unorderedFilterChain, pc, pc.extractSource(element));
// The list of filter beans
List<BeanMetadataElement> filterChain = new ManagedList<>();
for (OrderDecorator od : unorderedFilterChain) {
filterChain.add(od.bean);
}
return createSecurityFilterChainBean(element, pc, filterChain);
}
此时 HttpSecurityBeanDefinitionParser 的 parse 方法,filterChains.add (createFilterChain (element,pc)) 就是注册各个 filter bean 定义的代码,通过断点调试可以发现。
1)其中 forceAutoConfig 就是读取 <http auto-config=''true''...></http>,如果 auto-config=true,那么在 HttpConfigurationBuilder、AuthenticationConfigBuilder 中会自动加载所有 security filter 的 bean 定义。
其中 AuthenticationConfigBuilder 中创建 filter BeanDefinition 代码:
createAnonymousFilter();
createRememberMeFilter(authenticationManager);
createBasicFilter(authenticationManager);
createFormLoginFilter(sessionStrategy, authenticationManager);
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
createX509Filter(authenticationManager);
createJeeFilter(authenticationManager);
createLogoutFilter();
createLoginPageFilterIfNeeded();
createUserDetailsServiceFactory();
createExceptionTranslationFilter();
HttpConfigurationBuilder 中创建 filter BeanDefinition 代码:
createCsrfFilter();
createSecurityContextPersistenceFilter();
createSessionManagementFilters();
createWebAsyncManagerFilter();
createRequestCacheFilter();
createServletApiFilter(authenticationManager);
createJaasApiFilter();
createChannelProcessingFilter();
createFilterSecurityInterceptor(authenticationManager);
createAddHeadersFilter();
createCorsFilter();
2)如果在 <http security="none" ...></http> 将会特殊处理,需要注意。
跟踪 spring applicationContext 中加载 bean
从上图解析到的 bean 就是加载 applicationContext-*.xml 的配置内容的 bean:
1)加载 applicationContext-base.xml 的相关 bean 定义:
其中前边的
loginController
indexController
org.springframework.context.annotation.internalConfigurationAnnotationProcessor // 处理 @Configuration 注解
org.springframework.context.annotation.internalAutowiredAnnotationProcessor // 处理 @Autowired、@Value、@Inject 注解
org.springframework.context.annotation.internalCommonAnnotationProcessor // 处理 @PostConstruct、@PreDestroy、@Resource、@WebServiceRef
org.springframework.context.event.internalEventListenerProcessor // 处理 @EventListener 注解
org.springframework.context.event.internalEventListenerFactory
multipartResolver // 定义的文件上传解析器 bean
这些都是在加载 applicationContext-base.xml 时,加载的相关 bean 定义。
上边 org.springframework.context 的 bean 定义在 spring-context-5.2.0.RELEASE-sources.jar!/org/springframework/context/annotation/AnnotationConfigUtils.java 中。
其中定义的各个 bean 的对应的 BeanPostProcessor 类:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor 对应的类 org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor 对应的类 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor 对应的类 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
org.springframework.context.annotation.internalPersistenceAnnotationProcessor 对应的类 org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
org.springframework.context.event.internalEventListenerProcessor 对应的类 org.springframework.context.event.EventListenerMethodProcessor
org.springframework.context.event.internalEventListenerFactory 对应的类 org.springframework.context.event.DefaultEventListenerFactory
2)加载 applicationContext-security.xml 的相关 bean 定义:
8 = "org.springframework.security.filterChains"
9 = "org.springframework.security.filterChainProxy"
10 = "org.springframework.security.web.DefaultSecurityFilterChain#0"
11 = "org.springframework.security.web.PortMapperImpl#0"
12 = "org.springframework.security.web.PortResolverImpl#0"
13 = "org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0"
14 = "org.springframework.security.authentication.ProviderManager#0"
15 = "requestDataValueProcessor"
16 = "org.springframework.security.web.csrf.LazyCsrfTokenRepository#0"
17 = "org.springframework.security.web.context.HttpSessionSecurityContextRepository#0"
18 = "org.springframework.security.core.session.SessionRegistryImpl#0"
19 = "org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy#0"
20 = "org.springframework.security.web.savedrequest.HttpSessionRequestCache#0"
21 = "org.springframework.security.config.http.HttpConfigurationBuilder$SecurityContextHolderAwareRequestFilterBeanFactory#0"
22 = "org.springframework.security.config.http.HttpConfigurationBuilder$RoleVoterBeanFactory#0"
23 = "org.springframework.security.access.vote.AffirmativeBased#0"
24 = "org.springframework.security.web.access.intercept.FilterSecurityInterceptor#0"
25 = "org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator#0"
26 = "org.springframework.security.authentication.AnonymousAuthenticationProvider#0"
27 = "org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint#0"
28 = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0"
29 = "org.springframework.security.userDetailsServiceFactory"
30 = "org.springframework.security.web.DefaultSecurityFilterChain#1"
31 = "bCryptPasswordEncoder"
32 = "org.springframework.security.provisioning.InMemoryUserDetailsManager#0"
33 = "org.springframework.security.authentication.dao.DaoAuthenticationProvider#0"
34 = "org.springframework.security.authentication.DefaultAuthenticationEventPublisher#0"
35 = "org.springframework.security.authenticationManager"
今天的关于Spring Security Filter Ordering的分享已经结束,谢谢您的关注,如果想了解更多关于How Spring Security Filter Chain works、Java Spring Security @PostFilter 性能、java – Spring:异常启动过滤器springSecurityFilterChain、Java-Security (二):如何初始化 springSecurityFilterChain(FilterChainProxy)的相关知识,请在本站进行查询。
本文标签: