官网地址Architecture :: Spring Security
首先在官网下载示例
Hello Spring Security :: Spring Security
项目的代码非常简单,只有一个启动类,跑起来后会显示
Using generated security password: 47277899-ee11-44ca-b7fc-50c1001da7ab
这是因为SpringBoot自动配置的原因。Spring Boot自动为我们配置了bean。
启用Spring Security的预设设定,此设定会将Servlet过滤器建立为名为springSecurityFilterChain的Bean。此Bean负责应用程序中的所有安全性(保护应用程序URL、验证提交的用户名和密码、重定向到登录表单等)。 使用user的用户名和随机生成的密码创建UserDetailsService Bean,该密码将记录到控制台。 在Servlet容器中为每个请求注册名为springSecurityFilterChain的Bean的过滤器(Filter)。
Spring Boot配置不多,但它做了很多。功能概述如下:
-
需要经过身份验证的用户才能与应用程序进行任何交互
-
为您生成默认登录表单
-
让用户使用用户名user和登录到控制台的密码进行基于表单的身份验证(在前面的示例中,密码为47277899-ee11-44ca-b7fc-50c1001da7ab)
-
使用BCrypt保护密码存储
-
允许用户注销
-
CSRF攻击预防
-
会话固定保护
-
安全标头集成
-
安全请求的HTTP严格传输安全
-
X-Content-Type-Options集成
-
缓存控制(稍后可以由应用程序覆盖,以允许缓存静态资源)
-
X-XSS保护集成
-
X-Frame-Options集成有助于防止点击劫持
与以下Servlet API方法集成:
HttpServletRequest#getRemoteUser()
HttpServletRequest.html#getUserPrincipal()
HttpServletRequest.html#isUserInRole(java.lang.String)
HttpServletRequest.html#login(java.lang.String,java.lang.String)
HttpServletRequest.html#logout()
A Review of Filters
过滤器概述
Spring Security的Servlet支持是基于Servlet过滤器的,因此首先大致了解一下过滤器的作用是很有帮助的。下图显示了单个HTTP请求的处理程序的典型分层。
客户端向应用程序发送一个请求,容器创建一个FilterChain(过滤器链),它包含Filter实例和Servlet,这些实例和Servlet将根据请求URI的路径处理HttpServletRequest。在Spring MVC应用程序中,Servlet是DispatcherServlet的实例。一个Servlet最多只能处理一个HttpServletRequest和HttpServletResponse。但是,可以使用多个过滤器来:
-
防止调用下游Filter实例或Servlet。 在这种情况下,Filter通常会写入
HttpServletResponse
。 -
修改被下游过滤器实例和Servlet使用的
HttpServletRequest
或者HttpServletResponse
DelegatingFilterProxy
委托过滤器代理
Spring提供了一个名为DelegatingFilterProxy的Filter实现,它允许在Servlet容器的生命周期和Spring的ApplicationContext之间建立桥接。Servlet容器允许使用其自己的标准注册Filter实例,但它不知道Spring定义的Bean。您可以通过标准Servlet容器机制注册DelegatingFilterProxy,但将所有工作委托给实现Filter的Spring Bean。
DelegatingFilterProxy
的另外一个好处是 它允许延迟查找 Filter
bean 实例. 这很重要因为容器需要在能启动前注册Filter 实例. 然而Spring通常使用一个ContextLoaderListener
去加载Spring的bean,这直到需要注册Filter实例后才完成。(Filter懒加载)
FilterChainProxy
过滤器链代理
Spring Security的Servlet支持被包含在FilterChainProxy
中。FilterChainProxy
是Spring Security提供的一个特殊的Filter,它允许通过SecurityFilterChain委托(选择)许多Filter实例。由于FilterChainProxy
是一个bean,它通常被打包在一个DelegatingFilterProxy中。
下图展示了FilterChainProxy的角色
SecurityFilterChain
安全过滤器链
SecurityFilterChain is used by FilterChainProxy to determine which Spring Security Filter
instances should be invoked for the current request.
FilterChainProxy使用SecurityFilterChain来确定应为当前请求调用哪些Spring安全过滤器实例。
FilterChainProxy使用SecurityFilterChain来决定哪些Spring Security Filter
实例对于当前请求来说应该被调用。
在SecurityFilterChain中的Security Filter通常是bean,但是它们是被FilterChainProxy注册而不是DelegatingFilterProxy。FilterChainProxy直接向Servlet容器或DelegatingFilterProxy注册有许多优点。首先,他提供了一个面向所有SpringSecurity的Servlet支持的起点。因为这个原因,如果你想找到Spring Security的 Servlet 支持中的问题,添加一个断点在FilterChainProxy中是一个很好的开始位置。(SpringSecurity的Servlet支持大致意思是SpringSecurity提供的支持Servlet标准(Servlet、Filter)的bean)
其次,由于FilterChainProxy 是使用Spring Security的中心,因此它可以执行不被视为可选的任务。例如,它可以清除SecurityContext以避免内存泄漏。它还可以应用Spring Security的HttpFirewall来保护应用程序免受某些类型的攻击。
在上图中,FilterChainProxy
决定哪些SecurityFilterChain
应被使用。 只有第一个匹配到的SecurityFilterChain
被调用。 如果URL/api/message/
被请求,则它首先匹配SecurityFilterChain0
的模板路径/api/**
,所以只有SecurityFilterChain0
被调用,尽管它同样匹配SecurityFilterChainn
,如果一个为/messages/
的路径被请求,它不匹配SecurityFilterChain0
中的模板路径/api/**
,所以FilterChainProxy
继续尝试每个SecurityFilterChain
,假设没有其他SecurityFilterChain
实例匹配,SecurityFilterChainn
将被调用。
注意SecurityFilterChain0
只有三个security Filter被配置,然而SecurityFilterChainn
有四个security Filter实例被配置,记住每个SecurityFilterChain
能够独立存在并且可以隔离地配置是很重要的。事实上,如果应用程序想忽略某些确定的请求时,一个SecurityFilterChain
可能一个security Filter实例都没有。
Security Filters
安全过滤器
Security Filters通过 SecurityFilterChain API被插入到FilterChainProxy中。Filter实例的执行顺序很重要。通常来说,知道Spring Security的Filter
实例的顺序是不必要的,然而,有时候知道顺序是很有好处的。
以下是SpringSecurityFilter执行顺序的完整列表:
-
ChannelProcessingFilter
信道处理过滤器
-
WebAsyncManagerIntegrationFilter
Web异步管理器集成过滤器
-
SecurityContextPersistenceFilter
安全上下文持久性过滤器
-
HeaderWriterFilter
标头写入器过滤器
-
CorsFilter
跨域过滤器
-
CsrfFilter
客户过滤器
-
LogoutFilter
注销过滤器
-
OAuth2AuthorizationRequestRedirectFilter
OAuth2授权请求重定向过滤器
-
Saml2WebSsoAuthenticationRequestFilter
Saml2WebSso身份验证请求过滤器
-
X509AuthenticationFilter
X509身份验证过滤器
-
AbstractPreAuthenticatedProcessingFilter
抽象预身份验证处理过滤器
-
CasAuthenticationFilter
案例验证过滤器
-
OAuth2LoginAuthenticationFilter
OAuth2登录身份验证过滤器
-
Saml2WebSsoAuthenticationFilter
Saml2WebSso验证过滤器
-
DefaultLoginPageGeneratingFilter
默认登录页面生成过滤器
-
DefaultLogoutPageGeneratingFilter
默认注销页面生成过滤器
-
ConcurrentSessionFilter
并发会话过滤器
-
BearerTokenAuthenticationFilter
承载令牌身份验证过滤器
-
SecurityContextHolderAwareRequestFilter
安全性上下文持有者感知请求过滤器
-
JaasApiIntegrationFilter
JaasApi集成过滤器
-
RememberMeAuthenticationFilter
记住我的身份验证过滤器
-
AnonymousAuthenticationFilter
匿名身份验证过滤器
-
OAuth2AuthorizationCodeGrantFilter
OAuth2授权代码授予过滤器
-
SessionManagementFilter
会话管理过滤器
-
SwitchUserFilter
切换用户过滤器
Handling Security Exceptions
处理安全异常
ExceptionTranslationFilter允许将AccessDeniedException 和AuthenticationException 转换为HTTP响应。
ExceptionTranslationFilter
作为 Security Filters之一被插入到FilterChainProxy中,下图展示了ExceptionTranslationFilter
和其他组件之间的关系:
-
首先
ExceptionTranslationFilter
调用FilterChain.doFilter(request, response)
去调用程序的其他部分(也就是放行) -
如果用户是未经过认证的或者它是一个认证异常,那么就开始认证
-
HttpServletRequest
被保存,所以在认证成功后可以用来重放原始请求。
-
AuthenticationEntryPoint用于从客户端请求凭据。例如,它可能重定向到登录页面或发送“WWW-Authenticate”标头。
-
否则,如果他是一个
AccessDeniedException
那么就拒绝请求,然后AccessDeniedHandler
被调用来处理请求被拒绝。
-
提示:如果应用程序未引发AccessDeniedException或AuthenticationException,则ExceptionTranslationFilter不会执行任何操作。
ExceptionTranslationFilter
的伪代码如下:
try { filterChain.doFilter(request, response);//尝试放行 } catch (AccessDeniedException | AuthenticationException ex) {//抓取异常 if (!authenticated || ex instanceof AuthenticationException) {//判断异常类型 startAuthentication();//开始认证 } else { accessDenied();//拒绝请求 } }
Saving Requests Between Authentication
认证过程中保存请求
如“处理SecurityException”中所示,当请求没有身份验证并且是针对需要身份验证的资源时,需要保存请求,以便在身份验证成功后重新请求已验证的资源。在SpringSecurity中,这是通过使用RequestCache实现保存HttpServletRequest来完成的。
RequestCache
请求缓存
HttpServletRequest保存在RequestCache中。当用户成功进行身份验证时,RequestCache将用于重放原始请求。RequestCacheAwareFilter使用RequestCache保存HttpServletRequest。 默认情况下,使用HttpSessionRequestCache。下面的代码演示了如何自定义RequestCache实现,如果存在名为continue的参数,则该实现用于检查HttpSession中保存的请求。
RequestCacheAwareFilter
请求缓存感知过滤器
RequestCacheAwareFilter使用RequestCache保存HttpServletRequest。