概要
Spring是非常流行和成功的java应用开发框架,Spring Security正是Spring大家族中的一员。基于Spring的Spring Security框架,提供了一套Web应用安全性的完整解决方案。
整体结构
在Spring Security的结构设计中,认证(Authentication)和授权(Authorization),这两个部分也是Spring Security重要的核心功能。并且认证和授权是分开的,无论使用什么样的认证方式。都不会影响授权,这是两个独立的存在,这种独立带来的好处之一,就是可以非常方便的整合一些外部的解决方案
权限管理
基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问被授权的资源。
用户→认证→授权
认证
AuthenticationManager
在Spring Security中认证是由AuthenticationManager接口负责的,接口定义为:
- 返回Authentication表示认证成功
- 返回AuthenticationExeption异常,表示认证失败
AuthenticationManager主要实现类为ProviderManager,在ProviderManager中管理了众多AuthenticationProvider实例,在一次完整的认证过程中,Spring Security允许存在多个AuthenticationProvider,用来实现多种认证方式,这些AuthenticationProvider都是由ProviderManager进行统一管理的。
Authentication
认证以及认证成功的信息主要是由Authentication的实现类进行保存的,其接口定义为:
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)完成的
需要注意的是,默认过滤器并不是直接放在Web项目的原生过滤器中,而是通过一个FilterChainProxy来统一管理。Spring Security 中的过滤器链通过FilterChainProxy嵌入到wed项目的原生过滤器链中。FilterChainProxy作为一个顶层的管理者,将统一管理Security Filter。FilterChainProxy本身是通过Spring框架提供的DelegatingFilterProxy整合到原生过滤器中。
那么在Spring Security 中给我们提供哪些过滤器?默认情况下哪些过滤器会被加载
| 过滤器 | 过滤器作用 | 是否默认加载 |
|---|---|---|
| ChannelProcessingFilter | 过滤请求协议Http、HTTPS | no |
| 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认证的AccessToken | no |
| BasicAuthenticationFilter | 处理HttpBasic | yes |
| 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容器中,这个过滤器将负责所有的安全管理,包括用户认证、授权、重定向到登录页面等。
比较重要的三个过滤器
- 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>
当我们引入依赖后,再次访问我们的测试接口,会被一个登录接口所拦截。只有登录才能访问我们的网页。
默认用户是user,密码输出在控制台
结语
这就是一个最简单的Spring Security的deom,只需要引入一个依赖就可以完成登录的效果。但是这样的效果太简单了,在后续的开发中我们会改写Spring Security中的各种类来完成更为完善的效果,比如从数据库中获取用户数据登录,根据权限来限制用户的访问等。