同步操作将从 小牛肉/cs-wiki 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
在前面的几节中,已经对 Spring Security 有了一个比较全的使用体验了,这节我们简单的介绍下 Spring Security 基本的原理。
如果要对 Web 资源进行保护,最好的办法莫过于 Filter,要想对方法调用进行保护,最好的办法莫过于 AOP。
⭐ SpringSecurity 采用的是责任链的设计模式,它有一条很长的过滤器链:
Spring Security 提供的 Filter 有十多个,过滤器顺序从上到下:
WebAsyncManagerIntegrationFilter
将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。
SecurityContextPersistenceFilter(SecurityContext 持久化过滤器)
用来创建一个 SecurityContext
并存储在 SecurityContextHolder
中,因为后续 filter 需要用SecurityContext
存储的认证相关信息,所以需要在请求一开始就要把这些信息设置好,这样也能使在认证过程中对 SecurityContext
的任何修改都可以保存下来,并在请求结束后存储在 HttpSession 中(以在下次请求时使用)
ConcurrentSessionFilter(并发访问控制过滤器)
主要是判断 session 是否过期以及更新最新访问时间。
HeaderWriterFilter(请求头部写入过滤器)
往该请求的 Header 中添加相应的信息
CsrfFilter(CSRF过滤器)
为了防止跨站提交攻击。
LogoutFilter(退出过滤器)
退出当前登录的账号。
X509AuthenticationFilter(X509认证过滤器)
基于 X509 证书的认证过滤器。
AbstractPreAuthenticatedProcessingFilter
处理 form 登陆的过滤器,与 form 登陆有关的所有操作都是在此进行的。这个请求应该是用户使用 form 登陆后的提交地址。
CasAuthenticationFilter(CAS认证过滤器)
基于 CAS 的认证过滤器。
UsernamePasswordAuthenticationFilter(用户名密码认证过滤器)
基于用户名和密码的认证过滤器。
BasicAuthenticationFilter(basic认证过滤器)
此过滤器用于进行 basic 验证,功能与 AuthenticationProcessingFilter
类似,只是 Basic 验证方式相比较而言用的不是太多,默认会对密码进行 base64 加密。
SecurityContextHolderAwareRequestFilter
此过滤器用来包装客户的请求。通过查看其源码可以发现其 doFilter
方法中会创建一个包装类型 SecurityContextHolderAwareRequestWrapper
对 ServletRequest
对象进行包装,主要实现了 servlet api 的一些接口方法 isUserInRole
、getRemoteUser
,为后续程序提供一些额外的数据。即可以从 request
对象中获取到用户信息。
JaasApiIntegrationFilter
如果 SecurityContextHolder
中拥有的 Authentication
是一个 JaasAuthenticationToken
,那么该 Filter 将使用包含在 JaasAuthenticationToken
中的对象继续执行过滤器链。
RememberMeAuthenticationFilter(记住我认证过滤器)
当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统.
它先分析 SecurityContext
里有没有 Authentication
对象:
request
里有没有包含 remember-me
的 cookie 信息:如果有, 则解析出 cookie 里的验证信息, 判断是否有权限。AnonymousAuthenticationFilter(匿名认证过滤器)
用于支持 Spring Security 的匿名访问,适用于一些公共资源希望所有人都可以看到。
对于匿名访问的用户,Spring Security 支持为其建立一个匿名的 AnonymousAuthenticationToken
存放在 SecurityContextHolder
中,这就是所谓的匿名认证。这样在以后进行权限认证或者做其它操作时我们就不需要再判断 SecurityContextHolder
中持有的 Authentication
对象是否为 null
了,而直接把它当做一个正常的 Authentication
进行使用就OK了。
SessionManagementFilter
根据认证的安全实体信息跟踪 session,保证所有关联一个安全实体的 session 都能被跟踪到。
ExceptionTranslationFilter
解决在处理一个请求时产生的指定异常。
FilterSecurityInterceptor
简化授权和访问控制决定,委托一个 AccessDecisionManager 完成授权的判断。
SwitchUserFilter
SwitchUserFilter
是用来做账户切换的
上述这些 Filter 并不直接处理用户的认证,也不直接处理用户的授权,而是把它们交给了认证管理器和决策管理器。如下图:
对于这两种管理器,是不需要我们写代码的,Spring Security 提供了现成的类。这两个管理器自己也不做事,认证管理器把任务交给了 Provider,而决策管理器则把任务交给了 Voter,如下图:
对于 Voter
,我们一般选择 RoleVoter
就够用了,它会根据我们配置文件中的设置来决定是否允许某一个用户访问制定的Web资源。
SpringSecurity 提供了多个 Provider
的实现类,如果我们想用数据库来储存用户的认证数据,那么我们就选择 DaoAuthenticationProvider
。 而 DaoAuthenticationProvider
也是不直接操作数据库的,它把任务委托给了 ⭐ UserDetailService
,如下图:
⭐ 我们要做的,就是继承一个 UserDetailSevice
接口并且加入到容器中,他就是连接我们数据库和 Spring Security 的桥梁。UserDetailService
的要求也很简单,只需要一个重写 loadUserByUsername(String username)
方法,里面的逻辑通常是从数据库查找出对应用户名的密码然后构造一个org.springframework.security.core.userdetails.UserDetails
对象,Spring Security 会根据返回的这个带有正确用户信息的对象和前台传过来的用户名密码进行比对来判断是否认证通过。
因此,怎么设计数据库都可以,不管我们是用一个表还是两个表还是三个表,也不管我们是用户-授权,还是用户-角色-授权,还是用户-用户组-角色-授权,这些具体的东西 Spring Security 统统不关心,它只关心返回的那个User对象,至于怎么从数据库中读取数据,那就是我们自己的事了。
流程图:
流程说明:
客户端发起一个请求,进入 Security 过滤器链。
当到 LogoutFilter 的时候判断是否是登出路径,如果是登出路径则到 logoutHandler ,如果登出成功则到 logoutSuccessHandler 登出成功处理,如果登出失败则由 ExceptionTranslationFilter ;如果不是登出路径则直接进入下一个过滤器。
当到 UsernamePasswordAuthenticationFilter 的时候判断是否为登录路径,如果是,则进入该过滤器进行登录操作,如果登录失败则到 AuthenticationFailureHandler 登录失败处理器处理,如果登录成功则到 AuthenticationSuccessHandler 登录成功处理器处理,如果不是登录请求则不进入该过滤器。
当到 FilterSecurityInterceptor 的时候会拿到 uri ,根据 uri 去找对应的鉴权管理器,鉴权管理器做鉴权工作,鉴权成功则到 Controller 层否则到 AccessDeniedHandler 鉴权失败处理器处理。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。