Spring Security 学习笔记一

131 阅读9分钟

概要

Spring是非常流行和成功的java应用开发框架,Spring Security正是Spring大家族中的一员。基于Spring的Spring Security框架,提供了一套Web应用安全性的完整解决方案。

整体结构

在Spring Security的结构设计中,认证(Authentication)和授权(Authorization),这两个部分也是Spring Security重要的核心功能。并且认证和授权是分开的,无论使用什么样的认证方式。都不会影响授权,这是两个独立的存在,这种独立带来的好处之一,就是可以非常方便的整合一些外部的解决方案

权限管理

基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问被授权的资源。

用户→认证→授权

认证

AuthenticationManager

在Spring Security中认证是由AuthenticationManager接口负责的,接口定义为:

屏幕截图 2023-06-17 190519.png

  • 返回Authentication表示认证成功
  • 返回AuthenticationExeption异常,表示认证失败

AuthenticationManager主要实现类为ProviderManager,在ProviderManager中管理了众多AuthenticationProvider实例,在一次完整的认证过程中,Spring Security允许存在多个AuthenticationProvider,用来实现多种认证方式,这些AuthenticationProvider都是由ProviderManager进行统一管理的。

Authentication

认证以及认证成功的信息主要是由Authentication的实现类进行保存的,其接口定义为:

屏幕截图 2023-06-17 191615.png

  • getAuthorities():获取主体的身份验证权限。
  • getCredentials():获取已被验证的凭证。
  • getDetails() :获取关于用户身份认证的更多详细信息。
  • getPrincipal():获取已经被认证的主体。
  • isAuthenticated():指示是否已通过身份验证。
  • setAuthenticated(boolean):将对象标记为已通过或未通过身份验证。

SecurityContextHolder

SecurityContextHolder用来获取登录之后用户信息,Spring Security会将登录用户数据保存在Session中

授权

当完成认证后,接下来就是授权了。在Spring Security的授权体系中,有两个关键接口,

AccessDecisionManager

AccessDecisionManager(访问决策管理器)用来决定此次访问是否被允许

AccessDecisionVoter

AccessDecisionVoter(访问决定投票器)投票器会检查用户是否具备应有的角色,进而投票赞成、反对或者弃权票

ConfigAttribute

ConfigAttribute 用来保存授权时的角色信息

过滤器

Spring Security本质上就是一个过滤器链,这条过滤器链中有很多的过滤器。他们共同完成了,前端的请求拦截后放行的功能,只需要引入一个依赖,就可以让Spring Security 对应用进行保护。这是因为在引入依赖的同时也引入的许多Spring 默认的 Filter ,实现了认证授权等功能。所有Spring Security的功能都是基于过滤器(Filter)完成的

屏幕截图 2023-06-23 101720.png

需要注意的是,默认过滤器并不是直接放在Web项目的原生过滤器中,而是通过一个FilterChainProxy来统一管理。Spring Security 中的过滤器链通过FilterChainProxy嵌入到wed项目的原生过滤器链中。FilterChainProxy作为一个顶层的管理者,将统一管理Security Filter。FilterChainProxy本身是通过Spring框架提供的DelegatingFilterProxy整合到原生过滤器中。

那么在Spring Security 中给我们提供哪些过滤器?默认情况下哪些过滤器会被加载

过滤器过滤器作用是否默认加载
ChannelProcessingFilter过滤请求协议Http、HTTPSno
DisableEncodeUrlFilter禁用Web应用程序中的URL编码yes
WebAsyncManagerIntegrationFilter将WebAsyncManger与SpringSecurity上下文进行集成yes
SecurityContextPersistenceFilter在处理请求之前,将安全信息加载到SecurityContextHolder中yes
HeaderWriterFilter处理头信息加入响应中yes
CorsFilter处理跨域问题no
CsrfFilter处理CSRF攻击yes
LogoutFilter处理注销登录yes
OAuth2AuthorizationRequestRedirectFilter处理OAuth2认证重定向no
Saml2WebSsoAuthenticationRequestFilter处理SAML认证no
X509AuthenticationFilter处理X509认证no
AbstractPreAuthenticProcessingFilter处理预认证问题no
CasAuthenticationFilter处理CAS单点登录no
OAuth2LoginAuthenticationFilter处理OAuth2认证no
Saml2WebSsoAuthenticationFilter处理SAML认证no
UsernamePasswordAuthenticationFilter处理表单认证yes
OpenIEDAuthenticationFilter处理OpenID认证no
DefaultLoginPageGeneratingFilter配置默认登录页面yes
DefaultLogoutPageGeneratingFilter配置默认注销页面yes
ConcurrentSessionFilter处理Session有效期no
DigestAuthenticationFilter处理HTTP摘要认证no
BearerTokenAuthenticationFilter处理OAuth2认证的AccessTokenno
BasicAuthenticationFilter处理HttpBasicyes
RequestCacheAwareFilter处理请求缓存yes
SecurtyContextHolder AwareRequestFilter包装原始请求yes
JaasApilntegrationFiler处理JAAS认证no
RememberMeAuthenticationFilter处理RememberMe登录no
AnonymousAuthenticationFilter配置匿名认证yes
OAuth2AuthorizationCodeGrantFilter处理OAuth2认证中授权码no
SessionManagementFilter处理session并发问题yes
ExceptionTranslationFilter处理认证/授权中的异常yes
FilterSecurityInterceptor处理授权相关yes
SwitchUserFilter处理账户切换no

可以看出,Spring Security提供了30多个过滤器,默认情况下Spring Boot 在对Spring Security 进入自动化配置时,会创建一个名为SpringSecurityFilerChain的过滤器,并注入到Spring容器中,这个过滤器将负责所有的安全管理,包括用户认证、授权、重定向到登录页面等。

屏幕截图 2023-06-13 093957.png

比较重要的三个过滤器

  • FilterSecurityInterceptor
FilterSecurityInterceptor是Spring Security框架中的一个关键组件之一。它是一个过滤器,用于在请求到达受保护的资源之前执行安全检查和访问控制。
​
FilterSecurityInterceptor基于拦截过滤器(Intercepting Filter)模式实现,它位于Spring Security过滤器链中的特定位置,针对每个HTTP请求进行处理。
​
FilterSecurityInterceptor主要负责以下功能:
​
认证(Authentication):验证用户的身份,并基于身份提供相应的权限和角色。
​
授权(Authorization):根据用户的身份和请求的资源,判断用户是否有权限访问该资源。如果没有,将返回相应的错误或重定向到登录页等操作。
​
安全过滤(Security Filtering):对请求进行过滤,例如防止跨站请求伪造(CSRF)攻击,在请求到达受保护的资源之前进行必要的安全性检查。
​
FilterSecurityInterceptor通过与其他Spring Security过滤器(例如UsernamePasswordAuthenticationFilter和AccessDecisionManager等)协同工作,实现了整个安全认证和授权过程。
​
它的配置通常在Spring Security的配置文件中完成,可以定义如何处理认证、授权和安全过滤,以及相关的访问规则和策略。
​
FilterSecurityInterceptor在Spring Security中发挥着重要的作用,确保只有经过认证和授权的用户才能访问受保护的资源,从而实现了应用程序的安全性。
  • ExceptionTranslationFilter
​
ExceptionTranslationFilter 是 Spring Security 框架中的一个关键过滤器之一。它在认证和授权过程中处理异常,并将其转换为适当的响应或重定向。
​
ExceptionTranslationFilter 主要负责以下功能:
​
异常处理:捕获 Spring Security 中的异常,例如未认证的请求、访问被拒绝等异常。
​
异常翻译:将这些异常转换为适当的响应,例如重定向到登录页面、返回自定义的错误信息等。
​
安全上下文更新:在异常处理过程中,ExceptionTranslationFilter 会更新当前 SecurityContext 的状态,以反映出现的异常情况。
ExceptionTranslationFilter 的位置是在 Spring Security 过滤器链中的一个特定位置,通常是在过滤器链的末尾。它可以拦截其他过滤器中抛出的异常,并采取适当的措施来处理这些异常。
​
通常,ExceptionTranslationFilter 与其他过滤器(例如 FilterSecurityInterceptor)协同工作,以提供完整的认证和授权异常处理机制。它帮助应用程序在出现异常时,提供友好的错误提示和适当的重定向。
​
通过配置 Spring Security 的安全配置文件,你可以定义自定义的异常处理策略和重定向规则,以满足应用程序的特定需求。
  • UsernamePasswordAuthenticationFilter
​
UsernamePasswordAuthenticationFilter 是 Spring Security 框架中的一个过滤器,用于处理基于用户名和密码的身份认证。
​
UsernamePasswordAuthenticationFilter 主要负责以下功能:
​
拦截登录请求:该过滤器会拦截所有经过的登录请求,通常是在 “/login” 端点上。
​
提取用户名和密码:从登录请求中提取出用户名和密码信息。
​
创建 Authentication 对象:使用提取到的用户名和密码创建一个 Authentication 对象,表示用户的身份认证请求。
​
委托给 AuthenticationManager:将 Authentication 对象委托给 AuthenticationManager 进行进一步的验证和身份认证过程。
​
处理认证结果:根据 AuthenticationManager 的返回结果,处理身份认证成功或失败的情况,例如生成认证成功的令牌或返回认证失败的错误信息。
​
与成功处理器(AuthenticationSuccessHandler)和失败处理器(AuthenticationFailureHandler)协同工作:根据认证结果,将请求重定向到相应的页面或返回适当的错误信息。
​
通过配置 Spring Security 的安全配置文件,你可以定制 UsernamePasswordAuthenticationFilter 的行为和属性,例如登录端点、用户名和密码参数的名称、登录请求的方法等。
​
UsernamePasswordAuthenticationFilter 是 Spring Security 中一个核心的过滤器,用于处理用户名和密码的身份认证请求。它与其他过滤器(如 ExceptionTranslationFilter 和 FilterSecurityInterceptor)一起工作,实现全面的认证和授权机制。

入门案例

创建项目

Spring Security是基于Spring开发的框架,所以我们第一步就是要创建一个Spring的项目

测试接口

既然是一个Web应用安全性的完整解决方案,我们就要暴露一个接口

@RestController
public class TestController {
​
    @GetMapping("/hello")
    public HttpResult hello(){
        return HttpResult.ok("hello world");
    }
}
//统一返回
@Data
public class HttpResult<T> {
    private Integer code;
    private String msg;
    private T data;
​
    public static HttpResult ok(String msg){
        HttpResult result = new HttpResult();
        result.setCode(GlobalConstants.HTTP_STATUS_OK);
        result.setMsg(msg);
        return result;
    }
​
    public static<T> HttpResult ok(String msg , T data){
        HttpResult result = new HttpResult<>();
        result.setCode(GlobalConstants.HTTP_STATUS_OK);
        result.setMsg(msg);
        result.setData(data);
        return result;
    }
​
    public static HttpResult fail(Integer code , String msg){
        HttpResult result = new HttpResult();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
}

这是一个非常简单的接口方法,所以就不解释了。我们只要知道我们可以畅通无阻的访问它即可

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

当我们引入依赖后,再次访问我们的测试接口,会被一个登录接口所拦截。只有登录才能访问我们的网页。

屏幕截图 2023-07-13 134202.png

默认用户是user,密码输出在控制台

屏幕截图 2023-06-13 085748.png

结语

这就是一个最简单的Spring Security的deom,只需要引入一个依赖就可以完成登录的效果。但是这样的效果太简单了,在后续的开发中我们会改写Spring Security中的各种类来完成更为完善的效果,比如从数据库中获取用户数据登录,根据权限来限制用户的访问等。