一、Spring Security 简介
Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架,用于保护 Java 应用程序,尤其是基于 Spring 的应用。它构建在 Spring 框架之上,能够轻松地集成到基于 Spring 的应用程序中,包括 Spring Boot 应用。
Spring Security 提供了以下核心功能:
- 认证(Authentication) :确认用户身份的过程。支持多种认证方式,如基于表单的认证、HTTP 基本认证、基于 Token 的认证(如 JWT - JSON Web Tokens)等。
- 授权(Authorization) :确定已认证用户是否有权访问特定资源。通过定义访问规则来实现,例如基于角色(如管理员、普通用户)或权限(如读取权限、写入权限)的访问控制。
- 防止常见攻击 :提供了内置的 CSRF(跨站请求伪造)保护、XSS(跨站脚本攻击)保护、SQL 注入防护、点击劫持防护等功能。
二、Spring Security 的基本架构
Spring Security 通过一系列的过滤器(Filter)来实现其安全功能。这些过滤器构成了 Spring Security 的核心架构,主要的过滤器包括:
- CsrfFilter :用于防止跨站点请求伪造攻击。
- BasicAuthenticationFilter :支持 HTTP 的标准 Basic Auth 的身份验证模块。
- UsernamePasswordAuthenticationFilter :支持 Form 表单形式的身份验证模块。
- DefaultLoginPageGeneratingFilter 和 DefaultLogoutPageGeneratingFilter :用于自动生成登录页面和注销页面。
- AuthorizationFilter :负责授权模块。
这些过滤器通过 FilterChainProxy
进行管理,FilterChainProxy
会根据匹配规则(如 URL 匹配)决定使用哪个 SecurityFilterChain
。而 SecurityFilterChain
又由零到多个 Filter 组成,这些 Filter 完成实际的安全功能。
三、Spring Security 的配置
1. 添加依赖
在 Spring Boot 项目中,只需添加 Spring Security 的启动器依赖,Spring Boot 会自动配置基本的 Spring Security 功能:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
添加依赖后,Spring Boot 会自动配置一个默认的用户(用户名是 “user”)和一个随机生成的密码,应用启动时会在控制台打印出来。
2. 基本配置
可以通过在 application.properties
或 application.yml
文件中进行一些基本配置,如设置默认的用户名、密码和角色:
spring.security.user.name=admin
spring.security.user.password=admin123
spring.security.user.roles=ADMIN
3. 自定义配置
通过创建一个配置类来实现更复杂的 Spring Security 配置:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.requestMatchers("/user/login").anonymous()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.httpBasic(Customizer.withDefaults());
return http.build();
}
}
在上述配置中:
authorizeHttpRequests
用于定义请求的授权规则。这里配置了/user/login
路径允许匿名访问,/admin/**
路径只有具有ADMIN
角色的用户才能访问,其他所有请求都需要经过身份验证。formLogin
启用了基于表单的登录功能。httpBasic
启用了 HTTP 基本认证功能。
四、用户认证与授权
1. 自定义用户认证
可以通过创建一个自定义的 UserDetailsService
类来实现用户认证:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 根据用户名从数据库或其他存储中获取用户信息
if ("admin".equals(username)) {
return User.builder()
.username("admin")
.password("{noop}admin123")
.roles("ADMIN")
.build();
} else {
throw new UsernameNotFoundException("User not found");
}
}
}
然后在配置类中注入自定义的 UserDetailsService
,并配置认证管理器:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
}
}
2. 角色权限访问
在控制器中定义一个 Admin 资源类,只有 admin 用户才能进行访问:
@RequestMapping("admin")
@RestController
public class AdminController {
@GetMapping("resourse")
public String AdminRole(){
return "这是只有管理员用户才能访问的资源";
}
}
五、密码加密
Spring Security 提供了多种密码编码器,如 BCryptPasswordEncoder
,用于对用户密码进行加密存储。
在配置类中使用 BCryptPasswordEncoder
:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.requestMatchers("/user/login").anonymous()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults());
return http.build();
}
}
可以创建一个测试类,将所有用户的密码改为 BCrypt 加密后的数据:
@Test
public void testUpdateAllPasswords() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encodedPassword = encoder.encode("123456");
LambdaUpdateWrapper<Users> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(Users::getPassword, encodedPassword);
boolean result = usersMapper.update(null, updateWrapper) > 0;
if (result) {
System.out.println("所有用户的密码更新成功!");
} else {
System.out.println("密码更新失败!");
}
}
六、高级安全配置
1. 跨域资源共享(CORS)
当应用需要从不同的域访问资源时,需要配置 CORS:
http
.cors().configurationSource(corsConfigurationSource())
.and()
.authorizeRequests()
// 其他配置
;
private CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin("*");
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
这个配置允许来自任何源的请求,任何 HTTP 方法和任何请求头,在开发环境中比较方便,但在生产环境中可能需要更严格的限制。
2. Remember - Me 功能
Spring Security 的 Remember - Me 功能允许用户在关闭浏览器并重新打开后,仍然保持登录状态。通过在用户登录成功后,在客户端(浏览器)存储一个加密的 Cookie 来实现。在后续的请求中,Spring Security 会检查这个 Cookie 来自动认证用户。可以在 Spring Security 配置中添加如下内容:
http
.rememberMe()
.tokenValiditySeconds(86400)
.key("myRememberMeKey");
这里设置了 Remember - Me 令牌的有效期为 86400 秒(一天),并指定了一个密钥用于加密和解密 Cookie。
七、总结
Spring Security 是 Spring 生态系统中的重要组成部分,提供了全面的安全功能,包括身份验证、授权、防止常见攻击等。通过集成到 Spring Boot 应用中,可以快速实现安全配置,保护应用程序的数据和资源安全。掌握 Spring Security 的基本配置、用户认证与授权、密码加密以及高级安全配置等内容,是构建安全可靠的 Spring 应用的关键。