参考地址:https://www.ycbbs.vip/?p=6765
参考地址:https://github.com/liuminglei/SpringSecurityLearning
一、SpringSecurity简介
1.1 什么是SpringSecurity
- Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案
- 一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权 (Authorization)两个部分,这两点也是 Spring Security 重要核心功能
1.2 认证和授权
1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认 证过程。通俗点说就是系统认为用户是否能登录
2)用户授权指的是:验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的 权限。通俗点讲就是系统判断用户是否有权限去做某些事情。
1.3 Springsecurity特点
- 和 Spring 无缝整合
- 全面的权限控制
- 专门为 Web 开发而设计,旧版本不能脱离 Web 环境使用。新版本对整个框架进行了分层抽取,分成了核心模块和 Web 模块。单独 引入核心模块就可以脱离 Web 环境。
- 重量级的安全框架
1.4 Shiro与Springsecurity对比
1.4.1 Shiro特点
Shiro是Apache 旗下的轻量级权限控制框架;Spring Security 是 Spring 家族中的一个安全管理框架
轻量级:Shiro 主张的理念是把复杂的事情变简单。针对对性能有更高要求 的互联网应用有更好表现
通用性:不局限于 Web 环境,可以脱离 Web 环境使用,在 Web 环境下一些特定的需求需要手动编写代码定制
1.4. 2 Shiro与Springsecurity对比
Shiro是Apache 旗下的轻量级权限控制框架;Spring Security 是 Spring 家族中的一个重量级的安全管理框架
常见组合:
SSM + Shiro
Spring Boot/Spring Cloud + Spring Security
二、SpringSecurity模块划分及含义
- 核心 spring-security-core.jar
- 远程处理 spring-security-remoting.jar
- 网页 spring-security-web.jar
- 配置 spring-security-config.jar
- LDAP spring-security-ldap.jar
- ACL spring-security-acl.jar
- CAS spring-security-cas.jar
- OpenID spring-security-openid.jar
- Test spring-security-test.jar
2.1 核心 spring-security-core.jar
包含身份验证和访问控制类和接口,远程支持和基本配置API. 使用Spring-security的任何应用程序都需要此模块. 支持独立的应用程序,远程客户端,方法(服务层)安全性和JDBC用户配置. 包含包:
- org.springframework.security.core
- org.springframework.security.access
- org.springframework.security.authentication
- org.springframework.security.provisioning
2.2 远程处理 spring-security-remoting.jar
提供与Spring Remoting的集成. 除非你非要编写使用Spring Remoting的远程客户端,否则不需要这样做
主要包:
- org.springframework.security.remoting
2.3 网页 spring-security-web.jar
包含过滤器和相关的Web安全基础结构代码.任何与Servlet API依赖的东西. 如果你需要Spring Security Web认证服务和基于URL的访问控制,则需要它.
主要包:
- org.springframework.security.web
2.4 配置 spring-security-config.jar
包含安全名称空间解析代码和Java配置代码.如果你使用Spring Security XML名称空间精选配置或Spring Security 的java配置支持,则需要它.
主要包是:
- org.springframework.security.config
2.5 LDAP spring-security-ldap.jar
LDAP身份验证和配置代码.如果你需要使用LDAP用户条目,则为必须.
顶级软件包:
- org.springframework.security.ldap
2.6 ACL spring-security-acl.jar
专门的域对象ACL实现,用于将安全性应用于应用程序中的特定域对象实例.
顶级软件包:
- org.springframework.security.acls
2.7 CAS spring-security-cas.jar
Spring Security的CAS客户端集成.如果想通过CAS单点登录服务器使用Spring Security Web认证.
顶级软件包:
- org.springframework.security.cas
2.8 OpenID spring-security-openid.jar
OpenID web身份验证支持. 用于根据外部OpenID服务器对用户精选身份验证
顶级软件包;
- org.springframework.security.openid
2.9 Test spring-security-test.jar
支持Spring security 进行测试
三、SpringSecurity的工作流程
3.1 Security的设计思想
在Spring Security的
官方文档上有这么一句话:
Spring Security’s web infrastructure is based entirely on standard servlet filters.
Spring Security 的web基础是Filters。
Spring Security
的设计思想:即通过一层层的Filters来对web请求做处理。
一个web请求会经过一条过滤器链,在经过过滤器链的过程中会完成认证与授权,如果中间发现这条请求未认证或者未授权,会根据被保护API的权限去抛出异常,然后由异常处理器去处理这些异常。
如上图,一个请求想要访问到API就会以从左到右的形式经过蓝线框框里面的过滤器,其中绿色部分是我们本篇主要讲的负责认证的过滤器,蓝色部分负责异常处理,橙色部分则是负责授权。
3.2 SpringSecurity中涉及到的过滤及及作用
3.2.1 概述
如果你用过Spring Security
就应该知道配置中有两个叫formLogin
和httpBasic
的配置项,在配置中打开了它俩就对应着打开了上面的过滤器。
formLogin
对应着你form表单认证方式,即UsernamePasswordAuthenticationFilterhttpBasic
对应着Basic认证方式,即BasicAuthenticationFilter
换言之,你配置了这两种认证方式,过滤器链中才会加入它们,否则它们是不会被加到过滤器链中去的。
因为Spring Security
自带的过滤器中是没有针对JWT这种认证方式的,所以我们的demo中会写一个JWT的认证过滤器,然后放在绿色的位置进行认证工作。
3.2.2 常见过滤器说明
从启动是可以获取到过滤器链:(SpringSecurity从启动涉及到的过滤器)
- org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
- org.springframework.security.web.context.SecurityContextPersistenceFilter
- org.springframework.security.web.header.HeaderWriterFilter
- org.springframework.security.web.csrf.CsrfFilter
- org.springframework.security.web.authentication.logout.LogoutFilter
- org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter (重要过滤器)
- org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
- org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter
- org.springframework.security.web.authentication.www.BasicAuthenticationFilter
- org.springframework.security.web.savedrequest.RequestCacheAwareFilter
- org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
- org.springframework.security.web.authentication.AnonymousAuthenticationFilter
- org.springframework.security.web.session.SessionManagementFilter
- org.springframework.security.web.access.ExceptionTranslationFilter (重要过滤器)
- org.springframework.security.web.access.intercept.FilterSecurityInterceptor(重要过滤器)
1)WebAsyncManagerInterationFilter
这个过滤器就是集成SecurityContext到Spring异步执行机制中的WebAsyncManager。简答来说就是将SpringSecurity整合到Spring中区
2)SecurityContextPersistenceFilter
主要的作用就是使用SecurityContextRepository在session中保存或更新一个SecurityContext(存储单签的用户认证以及授权信息),并将SecurityContext给以后的过滤器使用,来为后续filter建立所需的上下文,如果没有这个过滤器的话后续的过滤器都无法被建立。(最最最核心的)
3) HeaderWriterFilter
向请求的Header中添加相应的信息,可在http标签内部使用security:headers来控制。但是这个标签仅用于jsp页面。
4) CsrfFilter
csrf又称跨域请求伪造,SpringSecurity会对所有post请求验证是否包含系统生成的csrf的token信息,如果没有token的话会被拦截到并且后台发出异常。这个拦截器起到防止csrf攻击的效果。
5) LogoutFilter
匹配 URL为/logout的请求,拦截到这个请求后实现用户退出,并且清除认证信息。
用途是在用户发送注销请求时,销毁用户session,清空SecurityContextHolder,
然后重定向到注销成功页面。可以与rememberMe之类的机制结合,在注销的同时清空用户cookie。
6) UsernamePasswordAuthenticationFilter
认证操作的过滤器,默认匹配URL为/login而且请求的方式必须为POST请求。
7) DefaultLoginPageGeneratingFilter
如果没有在配置文件中指定认证页面,则由该过滤器生成一个默认认证页面。简单来说就是没有指定登录页面的时候这个过滤器就会使用内部自带的登录页面(还挺好看的)。
8) DefaultLogoutPageGeneratingFilter
和之前的认证操作的过滤器差不多,如果没有指定退出页面的话这个过滤器就会自动生产一个默认的退出登录页面
9) BasicAuthenticationFilter
此过滤器会自动解析HTTP请求中头部名字为Authentication,且以Basic开头的头信息。
通过HttpSessionRequestCache内部维护了一个RequestCache,用于缓存HttpServletRequest。
10) SecurityContextHolderAwareRequestFilter
针对ServletRequest进行了一次包装,使得request具有更加丰富的API
11) AnonymousAuthenticationFilter
当SecurityContextHolder中认证信息为空,则会创建一个匿名用户存入到SecurityContextHolder中。SpringSecurity为了兼容未登录的访问,也走了一套认证流程,只不过是一个匿名的身份。
SecurityContextRepository限制同一用户开启多个会话的数量。
13) ExceptionTranslationFilter
异常转换过滤器位于整个springSecurityFilterChain的后方,用来转换整个链路中出现的异常。
14)FilterSecurityInterceptor
获取所配置资源访问的授权信息,根据SecurityContextHolder中存储的用户信息来决定其是否有权限。(最最最重要的)
用户的权限控制都包含在这个过滤器中。
功能一:如果用户尚未登陆,则抛出AuthenticationCredentialsNotFoundException“尚未认证异常”。
功能二:如果用户已登录,但是没有访问当前资源的权限,则抛出AccessDeniedException“拒绝访问异常”。
功能三:如果用户已登录,也具有访问当前资源的权限,则放行。
所有的过滤器都会实现SpringSecurityFilter安全过滤器。。。
四、SpringSecurity中重要概念
知道了Spring Security的大致工作流程之后,我们还需要知道一些非常重要的概念也可以说是组件:
- SecurityContext:上下文对象,
Authentication
对象会放在里面。- SecurityContextHolder:用于拿到上下文对象的静态工具类。
- Authentication:认证接口,定义了认证对象的数据形式。
- AuthenticationManager:用于校验
Authentication
,返回一个认证完成后的Authentication
对象。
4.1 SecurityContext 上下文对象
上下文对象,认证后的数据就放在这里面,接口定义如下:
public interface SecurityContext extends Serializable {
// 获取Authentication对象
Authentication getAuthentication();
// 放入Authentication对象
void setAuthentication(Authentication authentication);
}
这个接口里面只有两个方法,其主要作用就是get or set Authentication
。
4.2 SecurityContextHolder SecurityContext的工具类
public class SecurityContextHolder {
public static void clearContext() {
strategy.clearContext();
}
public static SecurityContext getContext() {
return strategy.getContext();
}
public static void setContext(SecurityContext context) {
strategy.setContext(context);
}
}
可以说是SecurityContext
的工具类,用于get or set or clear SecurityContext
,默认会把数据都存储到当前线程中。
参考链接:SecurityContextHolder及SecurityContextHolderStrategy详解:https://blog.csdn.net/liuminglei1987/article/details/110130556
4.3 Authentication 用户身份对象
public interface Authentication extends Principal, Serializable {
// 获取用户权限,一般情况下获取到的是 用户的角色信息
Collection<? extends GrantedAuthority> getAuthorities();
//获取证明用户认证的信息,通常情况下获取到的是密码等信息
Object getCredentials();
//获取用户的额外信息,(这部分信息可以是我们的用户表中的信息)
Object getDetails();
//获取用户身份信息,在未认证的情况下获取到的是用户名, 在已认证的情况下获取到的是 UserDetails
Object getPrincipal();
//获取当前 Authentication 是否已认证
boolean isAuthenticated();
//设置当前 Authentication 是否已认证(true or false)
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
Authentication
只是定义了一种在SpringSecurity进行认证过的数据的数据形式应该是怎么样的,要有权限,要有密码,要有身份信息,要有额外信息。
4.4 AuthenticationManager
public interface AuthenticationManager {
// 认证方法
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
AuthenticationManager
定义了一个认证方法,它将一个未认证的Authentication
传入,返回一个已认证的Authentication
,默认使用的实现类为:ProviderManager。