最新Spring Security实战教程(三)Spring Security 的底层原理解析

06-01 1609阅读

最新Spring Security实战教程(三)Spring Security 的底层原理解析

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志

🎐 个人CSND主页——Micro麦可乐的博客

🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战

🌺《RabbitMQ》专栏主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战

🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解

💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程

🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整

♥️《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术

如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

最新Spring Security实战教程(三)Spring Security 的底层原理解析

  • 1. 前言
    • 回顾过滤器 Filter
    • 委托过滤代理 DelegatingFilterProxy
    • 过滤链代理 FilterChainProxy
    • 安全过滤链 SecurityFilterChain
    • 2. 核心架构
    • 3. 身份认证流程详解
      • ❶ 请求拦截与过滤器链
      • ❷ AuthenticationManager 与 ProviderManager
      • ❸ 认证提供者(AuthenticationProvider)
      • 4. 授权机制解析
        • ❶ FilterSecurityInterceptor 工作原理
        • ❷ AccessDecisionManager与决策流程
        • 5. 自定义扩展点与源码调试
        • 6. 总结

          回顾链接:

          最新Spring Security实战教程(一)初识Spring Security安全框架

          最新Spring Security实战教程(二)表单登录定制到处理逻辑的深度改造

          1. 前言

          相信通过前面两个章节的讲解,大家已经对 Spring Security 有了一个初步认识,今天这个章节我们主要聊一聊 Spring Security 的底层原理。为什么我们只要简单的一个配置就可以实现我们想要的功能?实际上 Spring Security 的 Servlet 支持就是基于 Servlet 过滤器 Filter!

          官方文档参考:https://docs.spring.io/spring-security/reference/servlet/architecture.html

          回顾过滤器 Filter

          以下引入官方文档的示例图来回顾一下,单个 HTTP 请求的处理程序的典型分层,

          最新Spring Security实战教程(三)Spring Security 的底层原理解析

          开发者就可以针对每一个Filter过滤器中对请求进行修改或增强

          委托过滤代理 DelegatingFilterProxy

          Spring 提供了一个Filter名为 DelegatingFilterProxy 的实现,它可以在 Servlet容器 和 Spring容器 之间建立桥梁。

          最新Spring Security实战教程(三)Spring Security 的底层原理解析

          为什么需要一个桥梁? 因为 Servlet 容器并不知道 Spring 容器中定义的 Bean,那么就需要一个代理,帮助我们将 Servlet 容器中的 Filter 实例委托给 Spring 容器管理,观察下面的代码原理

          //原始Servlet Filter
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
              chain.doFilter(request, response); 
          }
          //模拟DelegatingFilterProxy伪代码 
          // 1、获取已注册为 Spring Bean 的 Filter
          // 2、将工作委托给 Spring Bean
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
          	Filter delegate = getFilterBean(someBeanName);
          	delegate.doFilter(request, response);
          }
          

          过滤链代理 FilterChainProxy

          Spring Security 的Servlet支持包含在 FilterChainProxy 中。 FilterChainProxy 是 Spring Security 提供的一个特殊的Filter,它允许通过Filter委托给许多SecurityFilterChain 实例

          最新Spring Security实战教程(三)Spring Security 的底层原理解析

          安全过滤链 SecurityFilterChain

          SecurityFilterChain 被 FilterChainProxy 用来确定应该为当前请求调用哪些 Spring Security Filter实例列表

          最新Spring Security实战教程(三)Spring Security 的底层原理解析

          下图显示了多个 SecurityFilterChain 实例:

          最新Spring Security实战教程(三)Spring Security 的底层原理解析

          在上图中,由 FilterChainProxy 决定应该使用哪个 SecurityFilterChain (仅调用第一个匹配的SecurityFilterChain)

          • 如果请求的URL为/api/messages/,则它首先匹配SecurityFilterChain0的/api/**模式
          • 如果请求的URL为/messages/,则它与SecurityFilterChainn匹配
          • 依次查找匹配…

            从上面图解中,我们可以总结 Spring Security 为开发者提供了一整套基于过滤器链(Filter Chain)的安全防护机制。从用户发起 HTTP 请求,到经过多个安全过滤器的逐层检查,直至最终认证与授权完成。

            我们来看一下 Spring Security 默认 DefaultSecurityFilterChain 启动的时候,默认加载的 16 个过滤器

            最新Spring Security实战教程(三)Spring Security 的底层原理解析

            Spring Security 已经帮我们封装了大部分的过滤器,实际上我们主要关注以下两个方面即可:

            • 身份认证流程:如何通过表单登录(或其他方式)实现用户身份验证,及其内部如何利用 AuthenticationManager、ProviderManager 和多个 AuthenticationProvider 协同工作。
            • 授权机制解析:如何通过安全拦截器(如 AbstractSecurityInterceptor)实现方法级别和 URL 级别的权限控制。

              2. 核心架构

              在 Spring Security 中,整个安全流程围绕着一个核心组件展开:FilterChainProxy。它负责拦截所有 HTTP 请求,并将其传递给预先配置好的多个安全过滤器。这些过滤器中,最关键的包括:

              • UsernamePasswordAuthenticationFilter:处理基于表单提交的登录请求。
              • BasicAuthenticationFilter:处理 HTTP Basic 认证请求。
              • FilterSecurityInterceptor:负责权限授权,调用 AccessDecisionManager 来判定当前用户是否有权访问目标资源。

                下面是一个简单的架构示意图,帮助你直观了解整个流程:

                最新Spring Security实战教程(三)Spring Security 的底层原理解析

                图解说明

                当请求到达 FilterChainProxy 时,根据请求类型,系统会交由不同的过滤器处理:

                • 认证流程:例如表单登录时,由 UsernamePasswordAuthenticationFilter 拦截,调用 AuthenticationManager 进行身份校验。
                • 授权流程:FilterSecurityInterceptor 负责拦截已认证用户的请求,并通过 AccessDecisionManager 判断其权限是否足够。

                  3. 身份认证流程详解

                  ❶ 请求拦截与过滤器链

                  所有 HTTP 请求首先进入 FilterChainProxy,该类遍历预先配置好的过滤器链。以表单登录为例,UsernamePasswordAuthenticationFilter 会在匹配到指定 URL 后触发认证逻辑。

                  public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
                      // 构造时指定处理的 URL,如 "/perform_login"
                      public UsernamePasswordAuthenticationFilter() {
                          super(new AntPathRequestMatcher("/perform_login", "POST"));
                      }
                      @Override
                      public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
                              throws AuthenticationException {
                          // 从请求中提取用户名和密码
                          String username = obtainUsername(request);
                          String password = obtainPassword(request);
                          UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
                          
                          // 调用 AuthenticationManager 进行认证
                          return this.getAuthenticationManager().authenticate(authRequest);
                      }
                  }
                  

                  说明

                  这里的 attemptAuthentication 方法负责解析用户提交的数据,然后构造一个 UsernamePasswordAuthenticationToken 对象,并交由 AuthenticationManager 处理。

                  ❷ AuthenticationManager 与 ProviderManager

                  AuthenticationManager 是一个接口,其最常用的实现是 ProviderManager。ProviderManager 持有一系列 AuthenticationProvider,用于逐个尝试认证。

                  public class ProviderManager implements AuthenticationManager {
                      private List providers;
                      @Override
                      public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                          // 遍历所有 AuthenticationProvider
                          for (AuthenticationProvider provider : providers) {
                              if (provider.supports(authentication.getClass())) {
                                  Authentication result = provider.authenticate(authentication);
                                  if (result != null) {
                                      // 认证成功后返回已认证的 Authentication 对象
                                      return result;
                                  }
                              }
                          }
                          throw new ProviderNotFoundException("无法找到对应的 AuthenticationProvider");
                      }
                  }
                  

                  说明

                  ProviderManager 会遍历所有注册的 AuthenticationProvider(例如 DaoAuthenticationProvider、LdapAuthenticationProvider 等),直到某个 Provider 成功认证为止。如果没有 Provider 能够处理,认证将失败并抛出异常。

                  ❸ 认证提供者(AuthenticationProvider)

                  一个典型的 AuthenticationProvider(如 DaoAuthenticationProvider)主要完成以下工作:

                  • 通过 UserDetailsService 加载用户信息;
                  • 利用 PasswordEncoder 校验密码;
                  • 如果认证成功,构造一个包含用户权限信息的已认证 Authentication 对象。

                    下面是一个自定义 AuthenticationProvider 的简单示例:

                    @Component
                    public class CustomAuthenticationProvider implements AuthenticationProvider {
                        @Autowired
                        private MyUserDetailsService userDetailsService;
                        
                        @Autowired
                        private PasswordEncoder passwordEncoder;
                        @Override
                        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                            String username = authentication.getName();
                            String rawPassword = (String) authentication.getCredentials();
                            
                            UserDetails user = userDetailsService.loadUserByUsername(username);
                            if (user == null) {
                                throw new BadCredentialsException("用户不存在");
                            }
                            
                            if (!passwordEncoder.matches(rawPassword, user.getPassword())) {
                                throw new BadCredentialsException("密码错误");
                            }
                            
                            return new UsernamePasswordAuthenticationToken(username, rawPassword, user.getAuthorities());
                        }
                        @Override
                        public boolean supports(Class authentication) {
                            return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
                        }
                    }
                    

                    源码剖析

                    在 authenticate 方法中,我们可以看到 Spring Security 如何利用 UserDetailsService 与 PasswordEncoder 协同工作,确保只有正确的凭证才能获得认证成功的结果。


                    4. 授权机制解析

                    认证成功后,系统进入授权阶段。授权主要通过 FilterSecurityInterceptor 完成,该拦截器负责在请求被具体业务逻辑处理前检查用户是否有权限访问对应资源。

                    ❶ FilterSecurityInterceptor 工作原理

                    FilterSecurityInterceptor 继承自 AbstractSecurityInterceptor,其主要职责为:

                    • 获取当前请求对应的安全配置(如所需角色、权限等),通常由 SecurityMetadataSource 提供;
                    • 调用 AccessDecisionManager,依据用户权限集合决定是否允许访问;
                    • 若访问被拒绝,则抛出 AccessDeniedException。

                      以下代码展示了大致流程:

                      public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
                          @Autowired
                          private SecurityMetadataSource securityMetadataSource;
                          @Override
                          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                                  throws IOException, ServletException {
                              // 封装请求信息
                              FilterInvocation fi = new FilterInvocation(request, response, chain);
                              // 获取安全配置(资源需要的权限)
                              Collection attributes = securityMetadataSource.getAttributes(fi);
                              
                              // 若资源无安全配置,则直接放行
                              if (attributes == null || attributes.isEmpty()) {
                                  fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
                                  return;
                              }
                              
                              // 检查用户是否具有访问权限
                              InterceptorStatusToken token = super.beforeInvocation(fi);
                              try {
                                  fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
                              } finally {
                                  super.afterInvocation(token, null);
                              }
                          }
                      }
                      

                      图解说明

                      最新Spring Security实战教程(三)Spring Security 的底层原理解析

                      通过这种设计,Spring Security 能够灵活配置 URL、方法等不同层次的授权策略

                      ❷ AccessDecisionManager与决策流程

                      AccessDecisionManager 根据传入的用户权限集合、请求所需权限及上下文信息进行判断。常见实现包括 AffirmativeBased、ConsensusBased 和 UnanimousBased。

                      伪代码示例:

                      public class AffirmativeBased implements AccessDecisionManager {
                          @Override
                          public void decide(Authentication authentication, Object object, Collection configAttributes)
                                  throws AccessDeniedException {
                              for (ConfigAttribute attribute : configAttributes) {
                                  if (this.supports(attribute)) {
                                      // 如果任何一个决策者同意访问,则允许
                                      if (voter.vote(authentication, object, configAttributes) == AccessDecisionVoter.ACCESS_GRANTED) {
                                          return;
                                      }
                                  }
                              }
                              throw new AccessDeniedException("没有足够权限访问该资源");
                          }
                      }
                      

                      说明

                      这种投票机制允许开发者根据实际业务需求定制多重决策规则,保证授权过程既灵活又安全。


                      5. 自定义扩展点与源码调试

                      Spring Security 的设计充分考虑了扩展性。常见的扩展点包括:

                      • 自定义 Filter:在现有 FilterChain 中插入新的安全过滤器;
                      • 自定义 AuthenticationProvider:实现特定业务场景下的身份验证;
                      • 自定义 AccessDecisionManager:满足细粒度的授权需求;
                      • 扩展 SecurityMetadataSource:支持基于动态资源的权限配置。

                        在IDEA调试源码时,双击 shift 弹出源码搜索框,你可以通过断点跟踪 FilterChainProxy、AuthenticationManager、ProviderManager 的调用过程,进一步了解每个组件的具体职责与协作方式


                        6. 总结

                        通过本文的源码剖析,我们了解了 Spring Security 的核心架构与工作流程:

                        • 认证流程 从过滤器链的拦截,到 UsernamePasswordAuthenticationFilter 的处理,再到 AuthenticationManager 与多个 AuthenticationProvider 的协作。
                        • 授权流程 则通过 FilterSecurityInterceptor 获取安全配置,并调用 AccessDecisionManager 决策用户是否具有访问权限。

                          这些机制保证了 Spring Security 在面对复杂安全场景时依然具有高度的灵活性和扩展性。深入理解这些原理,有助于你在实际项目中更精准地定制安全策略,并针对性地进行功能扩展或问题排查。

                          如果本本章内容对您有所帮助,希望 一键三连 给博主一点点鼓励,如果您有任何疑问或建议,请随时留言讨论!


                          下一章节:最新Spring Security实战教程(四)基于内存的用户认证 - UserDetailsService实战开发

                          最新Spring Security实战教程(三)Spring Security 的底层原理解析

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码