Spring Security框架的主要作用是为基于Spring的企业应用系统提供声明式的安全访问控制解决方案。它是一个开源项目,旨在为Java应用程序提供强大和灵活的安全性解决方案,包括认证、授权、防护等多个方面。
认证与授权: Spring Security支持多种认证机制,如表单登录、HTTP基本认证、OAuth2、OpenID等,以及基于角色或权限的访问控制,提供细粒度的访问控制。
安全防护: 提供多种防护措施,如防止会话固定攻击、点击劫持、跨站请求伪造等攻击,保护应用免受安全威胁。
集成性: 与Spring框架以及其他第三方库和框架进行无缝集成,如Spring MVC、Thymeleaf、Hibernate等,便于开发者在已有的技术栈中快速集成安全功能。
**其他功能:**还包括单点登录(SSO)功能,可以将多个应用程序集成到一个中央身份验证系统中,提供可定制的集成与其他Spring框架,如Spring MVC和Spring Boot。
SecurityFilterChain:SecurityFilterChain是Spring Security的核心组件之一,负责处理所有的HTTP请求。它由一系列的过滤器组成,这些过滤器在请求处理的不同阶段执行安全检查。
AuthenticationManager:身份验证的核心接口,负责验证用户的凭证。它会调用相应的AuthenticationProvider来实现具体的验证逻辑。
UserDetailsService:加载用户的特定数据。通过实现该接口,可以从数据库或其他数据源中获取用户信息。
SecurityContext:SecurityContext用于存储用户的身份信息(Authentication对象),它包含了用户的权限和角色信息,允许应用程序在整个请求周期内访问该信息。
工作流程:
- 客户端发送请求到服务器。
- SecurityFilterChain拦截请求,并检查用户的身份信息。
- 如果用户未认证,跳转到登录页面。
- 用户提交凭证,经过AuthenticationManager进行身份验证。
- 验证成功后,用户的身份信息被存储在SecurityContext中。
- 根据用户的角色和权限,决定是否允许访问请求的资源。
简单总结 Spring Security 流程即为:构建 Filter 链、执行Filter 链。Filter 链的构建依赖用户显式创建 SecurityFilterChain 实例,最后被 WebSecurityConfiguration 包装为FilterChainProxy。
1.@EnableWebSecurity
该注解是通过类SecurityAutoConfiguration间接引入的。
该注解引入类WebSecurityConfiguration、SpringWebMvcImportSelector、HttpSecurityConfiguration、OAuth2ImportSelector。
类WebSecurityConfiguration负责提供Spring Security框架存在的11个Filter。
类HttpSecurityConfiguration负责实例化HttpSecurity实例。
2.WebSecurityConfiguration
如下伪代码所示WebSecurityConfiguration核心功能就是完成Filter实例的创建。
java
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private WebSecurity webSecurity;
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
@Autowired(required = false)
private HttpSecurity httpSecurity;
@Autowired(required = false)
void setFilterChains(List<SecurityFilterChain> securityFilterChains) {
this.securityFilterChains = securityFilterChains;
}
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
...
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
}
for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity);
}
return this.webSecurity.build();
}
@Autowired(required = false)
void setWebSecurityCustomizers(List<WebSecurityCustomizer> webSecurityCustomizers) {
this.webSecurityCustomizers = webSecurityCustomizers;
}
}
但是必须借助SecurityFilterChain才能实现,最终被IOC容器管理的过滤器类型为FilterChainProxy :
java
public class FilterChainProxy extends GenericFilterBean {
private List<SecurityFilterChain> filterChains;
public FilterChainProxy(List<SecurityFilterChain> filterChains) {
this.filterChains = filterChains;
}
}
web服务处理请求过程中也是在过滤器FilterChainProxy内部实现11个具体Filter依次顺序执行。
2.1.HttpSecurity
类HttpSecurityConfiguration负责实例化Scope类型为prototype的HttpSecurity实例。此时的HttpSecurity其相关属性均为默认值。
2.2.SecurityFilterChain
SecurityFilterChain实例的创建需要用户显式的通过HttpSecurity类完成。
java
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(registry -> registry
.requestMatchers(s).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher(HttpMethod.OPTIONS)).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*")).hasRole("role_user")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2Configurer -> oauth2Configurer.jwt(jwtConfigurer -> jwtConfigurer.jwtAuthenticationConverter(jwt -> {
Map<String, Collection<String>> realmAccess = jwt.getClaim("realm_access");
Collection<String> roles = realmAccess.get("roles");
var grantedAuthorities = roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.toList();
return new JwtAuthenticationToken(jwt, grantedAuthorities);
})))
;
httpSecurity.exceptionHandling(handleConfig -> handleConfig.accessDeniedHandler(m_AccessDeniedHandler));
return httpSecurity.build();
}
Security框架内部提供了唯一的实现类DefaultSecurityFilterChain。如下伪代码所示filters集合默认情况下存在11个过滤器。
java
public final class DefaultSecurityFilterChain implements SecurityFilterChain {
private final RequestMatcher requestMatcher;
private final List<Filter> filters;
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
this.requestMatcher = requestMatcher;
this.filters = new ArrayList<>(filters);
}
}
按照顺序分别为:DisableEncodeUrlFilter、WebAsyncManagerIntegrationFilter、SecurityContextHolderFilter、HeaderWriterFilter、LogoutFilter、BearerTokenAuthenticationFilter、RequestAttributeAuthenticationFilter、SecurityContextHolderAwareRequestFilter、AnonymousAuthenticationFilter、ExceptionTranslationFilter、AuthorizationFilter。
3.SecurityFilterChain构建标准流程
抽象类AbstractConfiguredSecurityBuilder常见的子类为HttpSecurity & WebSecurity。
类HttpSecurity内部存在两个重要字段属性:元素类型为OrderedFilter的列表集合的filters & 元素类型为SecurityConfigurer的Map集合之configurers。
java
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder{
private final RequestMatcherConfigurer requestMatcherConfigurer;
private List<OrderedFilter> filters = new ArrayList<>();
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
private FilterOrderRegistration filterOrders = new FilterOrderRegistration();
private AuthenticationManager authenticationManager;
}
字段filters维护的是上述所讲述的11种过滤器。
java
public abstract class AbstractConfiguredSecurityBuilder {
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();
private final Map<Class<?>, Object> sharedObjects = new HashMap<>();
}
字段 configurers 维护的是上述所讲述的类SecurityConfigurer的子类。
类HttpSecurity的作用就是构建顺序Filter链的过程,每个Filter的具体功能被封装在SecurityConfigurer中。所以需要探明Filter的创建以及Filter与SecurityConfigurer之间的关系。
3.1.SecurityConfigurer子类创建过程
HttpSecurity构建相关功能时都会创建与之相对应的抽象类 AbstractHttpConfigurer的子类,诸如此类~[cors,CorsConfigurer],[authorizeHttpRequests,AuthorizeHttpRequestsConfigurer],[oauth2ResourceServer,OAuth2ResourceServerConfigurer],...,等。
每个SecurityConfigurer子类最终都会被添加至HttpSecurity的属性configurers中。
以AuthorizeHttpRequestsConfigurer为例:该SecurityConfigurer主要是基于请求URL验证请求的合法性。
如下所示registery通常利用requestMatchers设置相关过滤条件:
java
//以下只是AuthorizeHttpRequestsConfigurer特有流程
.authorizeHttpRequests(registry -> registry
//默认registry为AuthorizationManagerRequestMatcherRegistry
.requestMatchers(s_AuthList).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher(HttpMethod.OPTIONS)).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*")).hasRole("role_user").anyRequest().authenticated()
)
requestMatchers方法接受三种类型的参数:字符串数组【路径正则表达式】、RequestMatcher类型的数组以及HttpMethod。返回值类型为AuthorizedUrl。
3.1.1.AuthorizedUrl
3.2.Filter创建过程
java
public abstract class AbstractConfiguredSecurityBuilder{
protected final O doBuild() throws Exception {
synchronized (this.configurers) {
this.buildState = BuildState.INITIALIZING;
beforeInit();
// 触发重写过该init方法的SecurityConfigurer子类
init();
this.buildState = BuildState.CONFIGURING;
beforeConfigure();
// 触发重写过该configure方法的SecurityConfigurer子类,创建与当前SecurityConfigurer对应的Filter
configure();
this.buildState = BuildState.BUILDING;
O result = performBuild();
this.buildState = BuildState.BUILT;
return result;
}
}
}
3.2.1.init
3.2.2. configure
以AuthorizeHttpRequestsConfigurer为例:过滤器AuthorizationFilter创建过程中默认得到的AuthorizationManager 的类型为:RequestMatcherDelegatingAuthorizationManager。
java
public final class AuthorizeHttpRequestsConfigurer{
public void configure(H http) {
AuthorizationManager<HttpServletRequest> authorizationManager = this.registry.createAuthorizationManager();
AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
authorizationFilter.setAuthorizationEventPublisher(this.publisher);
authorizationFilter.setShouldFilterAllDispatcherTypes(this.registry.shouldFilterAllDispatcherTypes);
authorizationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
http.addFilter(postProcess(authorizationFilter));
}
}
4.Filter
Spring Security本质上就是顺序Filter链执行过程,在执行目标方法之前或者在Servlet架构层完成对请求的验证过程。本章节以过滤器之AuthorizationFilter为例。
4.1.AuthorizationFilter
java
public class AuthorizationFilter extends GenericFilterBean {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain){
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
...
AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request);
this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, request, decision);
if (decision != null && !decision.isGranted()) {
// 当前过滤器直接拒绝请求,响应头存在:401 Unauthorized内容
throw new AccessDeniedException("Access Denied");
}
// 通过当前过滤器,执行下一个过滤器
chain.doFilter(request, response);
}
}
java
public final class RequestMatcherDelegatingAuthorizationManager{
private final List<RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>>> mappings;
public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
for (RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>> mapping : this.mappings) {
RequestMatcher matcher = mapping.getRequestMatcher();
MatchResult matchResult = matcher.matcher(request);
if (matchResult.isMatch()) {
AuthorizationManager<RequestAuthorizationContext> manager = mapping.getEntry();
// 返回授权决定AuthorizationDecision
return manager.check(authentication,
new RequestAuthorizationContext(request, matchResult.getVariables()));
}
}
return DENY;//说明当前过滤器直接拒绝当前请求
}
}
通过当前过滤器的表现形式为:返回granted为true的AuthorizationDecision实例。该实例返回之前请求必须满足RequestMatcher条件 & AuthorizationManager条件。
java
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
<version>3.3.3</version>
</dependency>
依赖spring-security-oauth2-authorization-server完全覆盖spring-boot-starter-oauth2-authorization-server。
java
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>1.3.2</version>
</dependency>
与 spring-security-oauth2-authorization-server 相比,spring-boot-starter-security依赖多了一个spring-aop的jar包依赖。
java
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.3.3</version>
</dependency>
综上所述,spring-security-oauth2-authorization-server 、spring-boot-starter-security两个依赖完全提供spring-security全部功能。