1. 概述

这篇文章是关于Spring Security的Java配置介绍,它允许用户在不使用XML的情况下轻松配置Spring Security。

Java配置是在Spring框架的Spring 3.1版本中添加的,并在Spring 3.2版本中扩展到Spring Security,其定义在一个被注解为@Configuration的类中。

2. Maven设置

要在Maven项目中使用Spring Security,首先需要在项目pom.xml中添加spring-security-core依赖:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.3.3.RELEASE</version>
</dependency>

最新的版本可以在这里找到。

3. 使用Java配置Web安全

让我们从一个基本的Spring Security Java配置示例开始:

@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) 
      throws Exception {
        auth.inMemoryAuthentication().withUser("user")
          .password(passwordEncoder().encode("password")).roles("USER");
    }
}

你可能已经注意到,配置设置了一个基于内存的简单身份验证配置。此外,从Spring 5开始,我们还需要一个PasswordEncoder bean:

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

4. HTTP安全

要在Spring中启用HTTP安全,我们需要创建一个SecurityFilterChain bean:

@Bean 
 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeRequests()
      .anyRequest().authenticated()
      .and().httpBasic();
    return http.build();
}

上述配置确保了应用程序的所有请求都通过表单登录或HTTP基本认证进行身份验证。

这与以下XML配置完全相同:

<http>
    <intercept-url pattern="/**" access="isAuthenticated()"/>
    <form-login />
    <http-basic />
</http>

5. 表单登录

有趣的是,Spring Security会根据启用的功能自动生成登录页面,并使用处理提交登录的默认URL:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeRequests()
      .anyRequest().authenticated()
      .and().formLogin()
      .loginPage("/login").permitAll();
    return http.build();
}

这里自动生成的登录页面方便快速上手。

6. 使用角色进行授权

现在,让我们配置一些简单的角色授权,以针对每个URL:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeRequests()
      .antMatchers("/", "/home").access("hasRole('USER')")
      .antMatchers("/admin/**").hasRole("ADMIN")
      .and()
      // some more method calls
      .formLogin();
    return http.build();
}

请注意,我们如何同时使用类型安全API(hasRole)和表达式基础API(access)。

7. 注销

如同Spring Security的许多其他方面,注销也提供了框架提供的良好默认功能。

默认情况下,注销请求会清除会话、清除任何身份验证缓存、清空SecurityContextHolder并重定向到登录页面。

这是一个简单的注销配置:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.logout();
    return http.build();
}

然而,如果你想对可用处理器有更多的控制,完整的实现将如下所示:

@Bean
 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.logout().logoutUrl("/my/logout")
      .logoutSuccessUrl("/my/index")
      .logoutSuccessHandler(logoutSuccessHandler) 
      .invalidateHttpSession(true)
      .addLogoutHandler(logoutHandler)
      .deleteCookies(cookieNamesToClear)
      .and()
      // some other method calls
    return http.build();
}

8. 身份验证

让我们看看另一种使用Spring Security进行身份验证的方式。

8.1. 内存身份验证

我们从一个简单的内存配置开始:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) 
  throws Exception {
    auth.inMemoryAuthentication()
      .withUser("user").password(passwordEncoder().encode("password")).roles("USER")
      .and()
      .withUser("admin").password(passwordEncoder().encode("password")).roles("USER", "ADMIN");
}

8.2. JDBC身份验证

要迁移到JDBC,你只需要在应用中定义一个数据源,并直接使用它:

@Autowired
private DataSource dataSource;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) 
  throws Exception {
    auth.jdbcAuthentication().dataSource(dataSource)
      .withDefaultSchema()
      .withUser("user").password(passwordEncoder().encode("password")).roles("USER")
      .and()
      .withUser("admin").password(passwordEncoder().encode("password")).roles("USER", "ADMIN");
}

当然,在这两个示例中,我们也需要像第3部分中所述那样定义PasswordEncoder bean。

9. 总结

在这篇快速教程中,我们概述了Spring Security的Java配置基础知识,并重点介绍了展示最简单配置场景的代码示例。