Changes in the new version of Spring Security configuration

Entering the SpringBoot2.7 era, some friends found that a commonly used class suddenly expired:

picture

In the era of Spring Security, this class is too important. Of course, expired classes can continue to be used, but if you decide to be awkward, you only need to read the comments a little bit, and you will basically understand how to play.

Let's take a look at the annotations of WebSecurityConfigurerAdapter:

picture

From this comment, we probably understand what's going on.

In the past, our custom class inherited from WebSecurityConfigurerAdapter to configure our Spring Security. We mainly configured two things:

  • configure(HttpSecurity)
  • configure(WebSecurity)

The former is mainly to configure the filter chain in Spring Security, while the latter is mainly to configure some path release rules.

Now in the comments of WebSecurityConfigurerAdapter, people have made the meaning very clear:

  1. If you want to configure the filter chain in the future, you can implement it by customizing the SecurityFilterChain Bean.
  2. If you want to configure WebSecurity in the future, you can do it through WebSecurityCustomizer Bean.

Then let's take a look at a simple example.

First, we create a new Spring Boot project and introduce Web and Spring Security dependencies. Note that Spring Boot chooses the latest 2.7.

picture

Next, we provide a simple test interface, as follows:

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "hello 江南一点雨!";
    }
}

Friends know that in Spring Security, by default, as long as dependencies are added, all interfaces of our project have been completely protected. Now to start the project and access /hellothe interface The name is user, and the password is randomly generated in the startup log of the project.

Now our first requirement is to use a custom user instead of the one provided by the system by default. This is simple. We only need to register an instance of UserDetailsService with the Spring container, as follows:

@Configuration
public class SecurityConfig {

    @Bean
    UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
        users.createUser(User.withUsername("javaboy").password("{noop}123").roles("admin").build());
        users.createUser(User.withUsername("江南一点雨").password("{noop}123").roles("admin").build());
        return users;
    }

}

That's it.

Of course, my current users are stored in the memory. If your users are stored in the database, you only need to provide the implementation class of the UserDetailsService interface and inject it into the Spring container. This has been mentioned many times in the vhr video (public number The background reply 666 has a video introduction), so I won’t repeat it here.

But if I want /hellothis interface to be accessed anonymously, and I hope that this anonymous access has not passed through the Spring Security filter chain, if in the past, we can rewrite configure(WebSecurity)the method for configuration, but now, we have to change the game:

@Configuration
public class SecurityConfig {

    @Bean
    UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
        users.createUser(User.withUsername("javaboy").password("{noop}123").roles("admin").build());
        users.createUser(User.withUsername("江南一点雨").password("{noop}123").roles("admin").build());
        return users;
    }

    @Bean
    WebSecurityCustomizer webSecurityCustomizer() {
        return new WebSecurityCustomizer() {
            @Override
            public void customize(WebSecurity web) {
                web.ignoring().antMatchers("/hello");
            }
        };
    }

}

The content that used to be in configure(WebSecurity)the method is now in the WebSecurityCustomizer Bean, and the configuration can be written here.

What if I also want to customize the login page, parameters, etc.? Read on:

@Configuration
public class SecurityConfig {

    @Bean
    UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
        users.createUser(User.withUsername("javaboy").password("{noop}123").roles("admin").build());
        users.createUser(User.withUsername("江南一点雨").password("{noop}123").roles("admin").build());
        return users;
    }

    @Bean
    SecurityFilterChain securityFilterChain() {
        List<Filter> filters = new ArrayList<>();
        return new DefaultSecurityFilterChain(new AntPathRequestMatcher("/**"), filters);
    }

}

The bottom layer of Spring Security is actually a bunch of filters, so our previous configuration in the configure(HttpSecurity) method is actually to configure the filter chain. Now configure the filter chain, we configure the filter chain by providing a SecurityFilterChain Bean, SecurityFilterChain is an interface, this interface has only one implementation class DefaultSecurityFilterChain, the first parameter to build DefaultSecurityFilterChain is the interception rule, that is, which paths need to be intercepted, The second parameter is the filter chain. Here I give an empty set, that is, our Spring Security will intercept all requests, and then walk around in an empty set, which is equivalent to not intercepting any requests. .

Restart the project at this time, and you will find /hellothat it can also be accessed directly, because this path does not pass through any filters.

In fact, I think the new way of writing is more intuitive than the old way of writing, and it is easier for everyone to understand the working mechanism of the filter chain at the bottom of Spring Security.

Some friends will say that this way of writing is different from what I wrote before! With this configuration, I don’t know what filters are in Spring Security. In fact, by changing the way of writing, we can configure this as before:

@Configuration
public class SecurityConfig {

    @Bean
    UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
        users.createUser(User.withUsername("javaboy").password("{noop}123").roles("admin").build());
        users.createUser(User.withUsername("江南一点雨").password("{noop}123").roles("admin").build());
        return users;
    }

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .csrf().disable();
        return http.build();
    }

}

This way of writing is actually not much different from the previous way of writing.

Alright, I won’t talk too much about the extra nonsense, you guys can try the latest gameplay~

Guess you like

Origin blog.csdn.net/weixin_40379712/article/details/130056716