我意识到Spring安全性构建在过滤器链上,它将拦截请求,检测(缺少)身份验证,重定向到身份验证入口点或将请求传递给授权服务,并最终让请求命中servlet或抛出安全性异常(未经认证或未经授权) . DelegatingFitlerProxy将这些过滤器粘合在一起 . 为了执行他们的任务,这些过滤器访问服务,例如UserDetailsService和AuthenticationManager .
链中的关键过滤器(按顺序)
-
SecurityContextPersistenceFilter(从JSESSIONID恢复身份验证)
-
UsernamePasswordAuthenticationFilter(执行身份验证)
-
ExceptionTranslationFilter(从FilterSecurityInterceptor捕获安全性异常)
-
FilterSecurityInterceptor(可能会抛出身份验证和授权异常)
我很困惑如何使用这些过滤器 . 是否为spring提供的form-login,UsernamePasswordAuthenticationFilter仅用于/ login,后面的过滤器不是? form-login名称空间元素是否自动配置这些过滤器?是否每个请求(已验证或未验证)都会到达非登录URL的FilterSecurityInterceptor?
What if I want to secure my REST API with JWT-token, which is retrieved from login? 我必须配置两个命名空间配置 http
标签,权限?其他一个用于/ login使用 UsernamePasswordAuthenticationFilter
,另一个用于REST URL,使用自定义 JwtAuthenticationFilter
.
配置两个 http
元素是否会创建两个 springSecurityFitlerChains
? UsernamePasswordAuthenticationFilter
默认关闭,直到我声明 form-login
?如何将 SecurityContextPersistenceFilter
替换为一个,它将从现有的 JWT-token
而不是 JSESSIONID
获得 Authentication
?
2 回答
Spring安全过滤器链是一个非常复杂和灵活的引擎 .
查看current stable release 4.2.1 documentation,13.3 Filter Ordering部分,您可以看到整个过滤器链的过滤器组织:
现在,我将逐一尝试你的问题:
配置
<security-http>
部分后,对于每个部分,您必须至少提供一种身份验证机制 . 这必须是我刚刚引用的Spring Security文档的13.3 Filter Ordering部分中与第4组匹配的过滤器之一 .这是最低有效安全性:http元素可以配置:
只是这样做,这些过滤器配置在过滤链代理:
注意:我通过创建一个简单的RestController来获取它们,它们@Autowires FilterChainProxy并返回它的内容:
在这里我们可以看到,仅通过使用一个最小配置声明
<security:http>
元素,包含所有默认过滤器,但它们都不是认证类型(13.3过滤器排序部分中的第4组) . 所以它实际上意味着只需声明security:http
元素,SecurityContextPersistenceFilter,ExceptionTranslationFilter和FilterSecurityInterceptor就会自动配置 .实际上,应该配置一个身份验证处理机制,甚至安全命名空间bean处理它的声明,在启动期间抛出错误,但可以绕过在
<http:security>
中添加entry-point-ref属性如果我在配置中添加一个基本
<form-login>
,这样:现在,filterChain将是这样的:
现在,在FilterChainProxy中创建并配置了这两个过滤器org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter和org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter .
所以,现在,问题:
是的,它用于尝试完成登录处理机制,以防请求与UsernamePasswordAuthenticationFilter url匹配 . 可以配置此URL或甚至更改其行为以匹配每个请求 .
您也可以在同一FilterchainProxy中配置多个身份验证处理机制(例如HttpBasic,CAS等) .
不,form-login元素配置UsernamePasswordAUthenticationFilter,如果你没有提供登录页面网址,它还会配置org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter,它以简单的自动生成登录结束页 .
默认情况下,只需创建没有
security:"none"
属性的<security:http>
元素,即可自动配置其他过滤器 .每个请求都应该到达它,因为它是负责请求是否有权访问所请求的URL的元素 . 但之前处理的一些过滤器可能会停止过滤器链处理而不会调用
FilterChain.doFilter(request, response);
. 例如,如果请求没有csrf参数,CSRF过滤器可能会停止过滤器链处理 .不,你不是被迫这样做的 . 您可以在同一个http元素中声明
UsernamePasswordAuthenticationFilter
和JwtAuthenticationFilter
,但这取决于每个过滤器的具体行为 . 这两种方法都是可能的,哪种方法最终取决于自己的喜好 .是的,这是真的
是的,你可以在我发布的每个配置中提出的过滤器中看到它
您可以避免使用SecurityContextPersistenceFilter,只需在
<http:element>
中配置session strategy即可 . 只需像这样配置:<security:http create-session="stateless" >
或者,在这种情况下,您可以使用另一个过滤器覆盖它,这样在
<security:http>
元素内:编辑:
这最终取决于每个过滤器本身的实现,但事实上后者的认证过滤器至少能够覆盖最终由前面的过滤器进行的任何先前认证 .
但是,如果一个http请求将Http标头作为Http标头并在请求体内部提供,那么两个过滤器将尝试执行将其委托给管理器的身份验证机制,但这可以很容易地避免简单地检查如果请求已经在每个过滤器的
doFilter()
方法开始时已经过身份验证 .拥有多个身份验证筛选器与拥有多个身份验证提供程序有关,但不要强制它 . 在我之前曝光的情况下,我有两个身份验证过滤器,但我只有一个身份验证提供程序,作为两个过滤器创建相同类型的Authentication对象,因此在这两种情况下,身份验证管理器都会将其委派给同一个提供程序 .
与此相反,我也有一个场景,我只发布一个UsernamePasswordAuthenticationFilter,但用户凭据都可以包含在DB或LDAP中,所以我有两个UsernamePasswordAuthenticationToken支持提供程序,AuthenticationManager委托从过滤器到提供程序的任何身份验证尝试有意识地验证凭证 .
因此,我认为很明显,身份验证过滤器的数量既不会决定身份验证提供程序的数量,也不会决定提供程序的数量来确定过滤器的数量 .
我之前没有仔细研究过这个过滤器,但是在你上一个问题之后我一直在检查它的实现,并且通常在Spring中,几乎所有东西都可以配置,扩展或覆盖 .
SecurityContextPersistenceFilter委托在SecurityContextRepository实现中搜索SecurityContext . 默认情况下,使用HttpSessionSecurityContextRepository,但可以使用过滤器的一个构造函数更改此值 . 因此,最好编写一个符合您需求的SecurityContextRepository,并在SecurityContextPersistenceFilter中对其进行配置,相信它已被证实的行为,而不是从头开始全部制作 .
不,
UsernamePasswordAuthenticationFilter
扩展AbstractAuthenticationProcessingFilter
,这包含RequestMatcher
,这意味着您可以定义自己的处理URL,此过滤器只处理RequestMatcher
匹配请求URL,默认处理URL为/login
.如果
UsernamePasswordAuthenticationFilter
执行chain.doFilter(request, response);
,以后的过滤器仍然可以处理请求 .关于core fitlers的更多细节
UsernamePasswordAuthenticationFilter
由<form-login>
创建,这些是Standard Filter Aliases and Ordering这取决于之前的装配工是否成功,但
FilterSecurityInterceptor
通常是最后的装配工 .是的,每个fitlerChain都有
RequestMatcher
,如果RequestMatcher
与请求匹配,请求将由fitler链中的fitlers处理 .如果您不配置模式,则默认
RequestMatcher
匹配所有请求,或者您可以配置特定URL(<http pattern="/rest/**"
) .如果你想了解更多关于fitlers的信息,我想你可以在spring security中查看源代码 .
doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)