• SpringSecurity 介绍/基本使用/加载流程/认证流程/权限访问流程/共享认证信息


    目录

    一、介绍与基本使用

    二、原理*

    2.1 过滤器链

    2.2 过滤器链加载流程

    2.3 认证流程

    2.4 权限访问流程

    2.5 请求间共享认证信息


    一、介绍与基本使用

            Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分,这两点也是Spring Security 重要核心功能。

            (1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问 该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认 证过程。通俗点说就是系统认为用户是否能登录

            (2)用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户 所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以 进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的 权限。通俗点讲就是系统判断用户是否有权限去做某些事情

            helloworld

            使用springInitizer创建项目,勾选上web、springsecurity。 

            1.创建配置类,继承WebSecurityConfigurerAdapter,重写 configure(HttpSecurity http)

    1. @Configuration
    2. public class SecurityConfig extends WebSecurityConfigurerAdapter {
    3. @Override
    4. protected void configure(HttpSecurity http) throws Exception {
    5. http.formLogin(); // 表单登录
    6. http.authorizeRequests() //认证配置
    7. .anyRequest() // 任何请求
    8. .authenticated(); // 都需要身份验证
    9. }
    10. }

             2.编写Controller

    1. @RestController
    2. public class helloController {
    3. @GetMapping("/hello")
    4. public String hello(){
    5. return "hello,springSecurity!";
    6. }
    7. }

            3.运行项目后地址栏键入localhost:8080/hello.会自动进入登录界面

            默认的用户名user 密码在项目启动的时候会在控制台打印

            4.登录后收到服务器的响应

    二、原理*

    2.1 过滤器链

            SpringSecurity 本质是一个过滤器链。所有过滤器如下:

            (1) WebAsyncManagerIntegrationFilter:将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。

            (2) SecurityContextPersistenceFilter:在每次请求处理之前将该请求相关的安全上 下文信息加载到 SecurityContextHolder 中,然后在该次请求处理完成之后,将 SecurityContextHolder 中关于这次请求的信息存储到一个“仓储”中,然后将 SecurityContextHolder 中的信息清除,例如在 Session 中维护一个用户的安全信息就是这个过滤器处理的。

            (3) HeaderWriterFilter:用于将头信息加入响应中。

            (4) CsrfFilter:用于处理跨站请求伪造。

            (5)LogoutFilter:用于处理退出登录。

            (6)UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中 获取用户名和密码。默认情况下处理来自 /login 的请求。从表单中获取用户名和密码 时,默认使用的表单 name 值为 username password,这两个值可以通过设置这个过滤器的 usernameParameter passwordParameter 两个参数的值进行修改。

            (7)DefaultLoginPageGeneratingFilter:如果没有配置登录页面,那系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面。

            (8)BasicAuthenticationFilter:检测和处理 http basic 认证。

            (9)RequestCacheAwareFilter:用来处理请求的缓存。

            (10)SecurityContextHolderAwareRequestFilter:主要是包装请求对象 request。         (11)AnonymousAuthenticationFilter:检测 SecurityContextHolder 中是否存在 Authentication 对象,如果不存在为其提供一个匿名 Authentication。

            (12)SessionManagementFilter:管理 session 的过滤器

            (13)ExceptionTranslationFilter:处理 AccessDeniedException 和 AuthenticationException 异常。

            (14)FilterSecurityInterceptor:可以看做过滤器链的出口。

            (15)RememberMeAuthenticationFilter:当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的 remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。

            Spring Security 采取过滤链实现认证授权,只有当前过滤器通过,才能进入下一个过滤器

            绿色部分认证过滤器,需要我们自己配置,可以配置多个认证过滤器。可以使用 SpringSecurity提供的认证过滤器,也可以自定义过滤器(例如短信验证)。都需要通过重写 configure(HttpSecurity http)配置,没有配置不生效。下面重点介绍以下三个过滤器:

            1.UsernamePasswordAuthenticationFilter 过滤器:该过滤器会拦截前端提交的 POST 方式的登录表单请求,并进行身份认证

            2.ExceptionTranslationFilter 过滤器:该过滤器不需要我们配置,对于前端提交的请求会 直接放行,捕获后续抛出的异常并进行处理(例如:权限访问限制)。

            3. FilterSecurityInterceptor 过滤器:该过滤器是过滤器链最后一个过滤器,根据资源权限配置判断当前请求是否有权限访问对应的资源。如果访问受限会抛出相关异常,并由 ExceptionTranslationFilter 过滤器进行捕获和处理。

    2.2 过滤器链加载流程

            1. Spring Boot 项目启动后,SecurityFilterAutoConfiguration类会加载 DelegatingFilterProxyRegistrationBean注册过滤器,名字-springSecurityFilterChain。        

            2.DelegatingFilterProxyRegistrationBean 注册成功后,该过滤器就被加载到了注册器中。DelegatingFilterProxy类通过 springSecurityFilterChain名字,得到了一个 FilterChainProxy过滤器,最终执行的是这个过滤器的 doFilter方法。

            2. FilterChainProxy过滤器包含的属性:过滤器链-List<SecurityFilterChain> filterChains

    它的doFilter方法中调用了doFilterInternal方法,里面就包含了所有过滤器这些过滤器都被封装进了 SecurityFilterChain对象

            3.doFilterInternal方法中会调用 getFilters方法,会从过滤器链中拿出所有拦截器,创建一个虚拟的过滤器链执行其doFilter方法。

    2.3 认证流程

            认证流程是在 UsernamePasswordAuthenticationFilter 过滤器中处理。

            1.当前端提交的是一个 POST 方式的登录表单请求,就会被该过滤器拦截,并进行身份认 证。该过滤器的 doFilter() 方法实现在其抽象父类AbstractAuthenticationProcessingFilter中。

                    1.1 首先判断是否是登录认证的请求,若是则放行,不是则进入下一步

                    1.2 调用子类UsernamePasswordAuthenticationFilter 中的attemptAuthentication进行认证返回的authResult对象封装了认证信息

                            1.2.1 判断是否是POST类型的提交

                            1.2.2 获取表单数据(username、password)

                            1.2.3 构造Authentication 对象,标记为未认证。返回的对象类型UsernamePasswordAuthenticationToken,是Authentication 接口实现类,该类有两个构造器:一个用于封装前端请求传入的未认证的用户信息(用户权限(null)、用户名、密码、标记(false)),一个用于封装认证成功后的用户信息(用户权限(集合)、UserDetails对象、密码、标记(true))

                            1.2.4 将请求中的一些属性信息设置到 Authentication 对象中,如remoteAddresssessionID

                            1.2.5 调用providerManager类的authenticate方法进行认证ProviderManager AuthenticationManager 接口的实现类。(ProviderManager内部会维护一个 List列表,存放多种认证方式。每种认证方式对应着一个 AuthenticationProvider,根据传入的 Authentication 类型委托对应的 AuthenticationProvider 进行用户认证。)

                                    1.2.5.1 获取Authentication 对象的类型

                                    1.2.5.2 获取认证方式列表的迭代器

                                    1.2.5.3 判断当前AuthenticationProvider是否适合当前 Authentication 对象

                                    1.2.5.4 调用当前AuthenticationProviderauthenticate方法进行认证(关联UserDetailService,将创建的Authentication 对象中的信息与数据库中存的UserDetails对比

                                    1.2.5.5 若认证成功,返回标记为已认证的Authentication 对象,将details信息拷贝到其中。调用 CredentialsContainer 接口定义的 eraseCredentials() 方法去除result中的敏感信息(密码),最后发布认证成功事件

                                    1.2.5.6 若认证失败,交给其父类AuthenticationManager处理。如果还是不行,抛异常。

                    1.3 对session策略进行处理(比如配置了session的最大并发数)

                    1.4 若认证成功,调用successfulAuthentication处理器

                            1.4.1 将认证成功的 Authentication 对象封装securityContext对象中,存入securityContextHolder是对ThreadLocal的封装,创建securityContext)中。

                            1.4.2 处理remeberMe

                            1.4.3 发布认证成功事件

                            1.4.4 调用认证成功处理器-onAuthenticationSuccess

                    1.5 若认证失败,调用unsuccessfulAuthentication处理器

                            1.5.1 清除该线程securityContextHolder中的securityContext对象

                            1.5.2 处理remeberMe

                            1.5.3 调用认证失败处理器-onAuthenticationFailure

    2.4 权限访问流程

            1.ExceptionTranslationFilter 过滤器

                    1.1 对前端提交的请求直接放行

                    1.2 捕获后续的异常并进行处理未认证权限不足

            2.FilterSecurityInterceptor 过滤器

                    2.1 根据资源权限配置判断是否有权限访问资源,若无则抛异常。        

                            2.1.1 获取当前 request 所对应的 ConfigAttribute权限信息

                            2.1.2 判断SecurityContext中有没有用户信息。如果没有则抛错,有则继续执行。

                            2.1.3 调用authenticateIfRequired方法校验是否通过认证(内部调用authenticationManager.authenticate()

                            2.1.4 调用AbstractSecurityInterceptor类的attemptAuthorization方法进行权限校验注意跟认证过程中的attemptAuthorization不一样

                            2.1.5 发布权限校验成功事件

                            2.1.6 创建SecurityContextAuthentication对象,更新用户信息

                    2.2 通过SpringMVCDispatcherServlet访问资源。

            注:Spring Security 的过滤器链是配置在 SpringMVC 的核心组件 DispatcherServlet 运行之前。也就是说,请求通过 Spring Security 所有过滤器, 不意味着能够正常访问资源,该请求还需要通过 SpringMVC拦截器链

    2.5 请求间共享认证信息

            一般认证成功后的用户信息是通过 Session 多个请求之间共享,那么 Spring Security 中是如何实现将已认证的用户信息对象 Authentication Session 绑定的呢?

            SecurityContextPersistenceFilter 过滤器的位置在所有过滤器最前面请求到来先进它响应返回最后一个通过它,所以在该过滤器中处理已认证的用户信息对象 Authentication Session 绑定。

            认证成功响应通过 SecurityContextPersistenceFilter 过滤器时,会从 SecurityContextHolder 取出封装了已认证用户信息对象 Authentication SecurityContext,放进 Session 中。

            当请求再次到来时,请求首先经过该过滤器,该过滤器会判断当前请求Session 是否存有 SecurityContext 对象,如果则将该对象取出再次放入 SecurityContextHolder 中,则创建空的。之后该请求所在的线程获得认证用户信息,后续的资源访问不需要进行身份认证

            当响应再次返回时,该过滤器同样从 SecurityContextHolder 取出 SecurityContext 对象,放入 Session 中。

  • 相关阅读:
    Kubernetes基础命令
    python学习
    安卓开发Java版——UI界面的设计
    元器件贸易企业,理应“以快制胜”
    【DETR 论文解读】End-to-End Object Detection with Transformer
    服务器数据恢复—raid5上层NTFS分区误删除/格式化的数据恢复案例
    JAVA最全面试题汇总基础篇(一)
    Python基础知识点入门
    (附源码)ssm考务管理系统 毕业设计 221504
    Qt入门(五)——文件操作、热键和鼠标的读取(txt窗口的实现)
  • 原文地址:https://blog.csdn.net/weixin_62427168/article/details/126385617