Spring Security架构和核心类详解
Spring Security架构和核心类详解
Spring Security是一个强大的安全框架,用于保护基于Spring的应用程序。它提供了认证、授权以及各种安全功能,如密码编码、会话管理等。本文将深入探讨Spring Security的核心架构和关键类,帮助开发者更好地理解和使用这个框架。
Spring Security框架概述
Spring Security通过一系列过滤器来实现安全功能。核心组件是DelegatingFilterProxy
,它在Servlet生命周期和Spring Bean之间搭建了一座桥梁。下面是一个简单的配置示例:
@Bean
public FilterRegistrationBean<Filter> filterRegistrationBean() throws Exception {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy();
delegatingFilterProxy.setTargetFilterLifecycle(true);
delegatingFilterProxy.setBeanName("myFilter");
filterRegistrationBean.setFilter(myFilter);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
在这个配置中,myFilter
是Servlet的过滤器,而DelegatingFilterProxy
是Spring提供的一个类,允许我们在Spring Bean中管理Servlet过滤器。
FilterChainProxy
是一个Bean,被包装在DelegatingFilterProxy
中。它类似于一个集合,每个元素是一个SecurityFilterChain
。每个SecurityFilterChain
内部又包含多个过滤器,如LogoutFilter
和UsernamePasswordAuthenticationFilter
等。
你可以把SecurityFilterChain
想象成一个班级,而FilterChainProxy
则是一个学校。需要注意的是,SecurityFilterChain
的匹配顺序非常重要,Spring Security会按照顺序执行匹配的第一个链。
认证核心代码
SecurityContextHolder
SecurityContextHolder
用于存储用户身份认证完毕后的认证信息。默认使用ThreadLocal
线程绑定方式存储信息。为了在请求结束时将信息保存到Session中,可以使用HttpSessionSecurityContextRepository
。
当需要在子线程中访问认证信息时,可以通过设置系统属性或使用DelegatingSecurityContextExecutorService
来解决。
GrantedAuthority
GrantedAuthority
实例表示授予用户的高级权限,如角色和范围。可以通过Authentication.getAuthorities()
获取当前用户的所有权限集合。
AuthenticationManager
AuthenticationManager
是认证的核心类,决定了Spring Security过滤器的执行流程。它传递的Authentication
对象只包含用户名和密码,认证成功后会填充完整信息并返回,否则会抛出AuthenticationException
异常。
ProviderManager
ProviderManager
相当于一个集合,每个元素都是AuthenticationProvider
类。这些认证提供者是最终执行认证的地方,每个提供者都是相互隔离的。如果轮询结束后没有一个提供者被执行,会抛出ProviderNotFoundException
。
AuthenticationProvider
AuthenticationProvider
接口定义了认证的核心方法:
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
}
supports
函数用于判断当前Authentication
是否支持该提供者。例如,DaoAuthenticationProvider
需要UsernamePasswordAuthenticationToken
类型的认证。
UsernamePasswordAuthenticationFilter
UsernamePasswordAuthenticationFilter
是Spring Security中常用的过滤器之一,主要用于处理基于用户名密码的认证请求。核心代码如下:
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
username = (username != null) ? username.trim() : "";
String password = obtainPassword(request);
password = (password != null) ? password : "";
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
DaoAuthenticationProvider
DaoAuthenticationProvider
提供了密码验证的具体实现:
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
if (authentication.getCredentials() == null) {
throw new BadCredentialsException();
}
String presentedPassword = authentication.getCredentials().toString();
if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword(/**/))) {
throw new BadCredentialsException(/**/);
}
}
此外,它还提供了密码加密方法升级和防止旁道攻击的功能。
UserDetailsService
UserDetailsService
用于从数据库或其他数据源加载用户信息。默认情况下,Spring Security将用户信息保存在内存中。如果需要从数据库中获取用户信息,可以重写这个接口:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
PasswordEncoder
PasswordEncoder
接口定义了密码加密和匹配的方法:
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
Spring Security默认使用DelegatingPasswordEncoder
,它可以支持多种加密算法。在实际项目中,通常会配置一个DelegatingPasswordEncoder
:
@Bean
public PasswordEncoder passwordEncoder() throws Exception {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
总结
Spring Security通过一系列过滤器和认证组件,提供了全面的安全保护功能。理解其核心架构和关键类的工作原理,对于开发安全的Spring应用程序至关重要。本文重点介绍了框架的整体架构和核心组件,后续将深入探讨登录成功后的处理流程、异常处理机制以及前后端分离场景下的应用。