1 Star 0 Fork 552

Leader / CS-Wiki

forked from 小牛肉 / cs-wiki 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
9-原理分析.md 8.02 KB
一键复制 编辑 原始数据 按行查看 历史
小牛肉 提交于 2021-07-11 21:36 . 🥽 更新目录结构

💫 Spring Security 原理分析


在前面的几节中,已经对 Spring Security 有了一个比较全的使用体验了,这节我们简单的介绍下 Spring Security 基本的原理。

1. Filter 过滤器

如果要对 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 方法中会创建一个包装类型 SecurityContextHolderAwareRequestWrapperServletRequest 对象进行包装,主要实现了 servlet api 的一些接口方法 isUserInRolegetRemoteUser,为后续程序提供一些额外的数据。即可以从 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 是用来做账户切换的

2. 认证管理器和决策管理器

上述这些 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对象,至于怎么从数据库中读取数据,那就是我们自己的事了。

3. Spring Security 流程

流程图

流程说明

  • 客户端发起一个请求,进入 Security 过滤器链。

  • 当到 LogoutFilter 的时候判断是否是登出路径,如果是登出路径则到 logoutHandler ,如果登出成功则到 logoutSuccessHandler 登出成功处理,如果登出失败则由 ExceptionTranslationFilter ;如果不是登出路径则直接进入下一个过滤器。

  • 当到 UsernamePasswordAuthenticationFilter 的时候判断是否为登录路径,如果是,则进入该过滤器进行登录操作,如果登录失败则到 AuthenticationFailureHandler 登录失败处理器处理,如果登录成功则到 AuthenticationSuccessHandler 登录成功处理器处理,如果不是登录请求则不进入该过滤器。

  • 当到 FilterSecurityInterceptor 的时候会拿到 uri ,根据 uri 去找对应的鉴权管理器,鉴权管理器做鉴权工作,鉴权成功则到 Controller 层否则到 AccessDeniedHandler 鉴权失败处理器处理。

📚 References

Java
1
https://gitee.com/mmbuy_admin/CS-Wiki.git
git@gitee.com:mmbuy_admin/CS-Wiki.git
mmbuy_admin
CS-Wiki
CS-Wiki
master

搜索帮助