Spring Security – Whitelist IP Range – Spring Security – 白名单IP范围

最后修改: 2018年 9月 12日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll discuss how to whitelist IP ranges in Spring Security.

在本教程中,我们将讨论如何在Spring Security中白名单IP范围

We’ll take a look at both Java and XML configurations. We’ll also see how to whitelist IP range using a custom AuthenticationProvider.

我们将看一下Java和XML的配置。我们还将看到如何使用一个自定义的AuthenticationProvider来白名单IP范围。

2. Java Configuration

2.Java配置

First, let’s explore the Java configuration.

首先,我们来探讨一下Java的配置。

We can use hasIpAddress() to allow only users with a given IP address to access a specific resource.

我们可以使用hasIpAddress()来只允许拥有特定IP地址的用户访问特定资源

Here’s a simple security configuration using hasIpAddress():

下面是一个使用hasIpAddress()的简单安全配置。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .antMatchers("/login").permitAll()
          .antMatchers("/foos/**").hasIpAddress("11.11.11.11")
          .anyRequest().authenticated()
          .and()
          .formLogin().permitAll()
          .and()
          .csrf().disable();
    }

    // ...

}

In this configuration,  only users with the IP address “11.11.11.11” will be able to access the ”/foos” resource. There’s also no need for users with the whitelisted IP to log in before they access the “/foos/” URL.

在这个配置中,只有IP地址为 “11.11.11.11 “的用户才能够访问”/foos “资源。也不需要让拥有白名单IP的用户在访问”/foos/”URL前登录。

If we want users with “11.11.11.11” IP to log in first, we can use the method in an expression of the form:

如果我们想让IP为 “11.11.11.11 “的用户先登录,我们可以在一个表达式中使用该方法。

//...
.antMatchers("/foos/**")
.access("isAuthenticated() and hasIpAddress('11.11.11.11')")
//...

3. XML Configuration

3.XML配置

Next, let’s see how to whitelist an IP range using XML configuration:

接下来,让我们看看如何使用XML配置将一个IP范围列入白名单。

We’ll use hasIpAddress() here as well:

我们在这里也将使用hasIpAddress()

<security:http>
    <security:form-login/>
    <security:intercept-url pattern="/login" access="permitAll()" />
    <security:intercept-url pattern="/foos/**" access="hasIpAddress('11.11.11.11')" />
    <security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>

// ...

4. Live Test

4.现场测试

Now, here’s a simple live test to make sure everything is working properly.

现在,这里有一个简单的现场测试,以确保一切都在正常工作。

First, we’ll make sure any user can access the home page after login:

首先,我们要确保任何用户在登录后都能访问主页。

@Test
public void givenUser_whenGetHomePage_thenOK() {
    Response response = RestAssured.given().auth().form("john", "123")
      .get("http://localhost:8082/");

    assertEquals(200, response.getStatusCode());
    assertTrue(response.asString().contains("Welcome"));
}

Next, we’ll make sure even authenticated users can’t access the “/foos” resource unless their IP is whitelisted:

接下来,我们将确保即使是认证用户也不能访问”/foos “资源,除非他们的IP是白名单。

@Test
public void givenUserWithWrongIP_whenGetFooById_thenForbidden() {
    Response response = RestAssured.given().auth().form("john", "123")
      .get("http://localhost:8082/foos/1");

    assertEquals(403, response.getStatusCode());
    assertTrue(response.asString().contains("Forbidden"));
}

Note that we aren’t able to access “/foos” resource from localhost “127.0.0.1” as only users with “11.11.11.11” are able to access it.

注意,我们无法从本地主机 “127.0.0.1 “访问”/foos “资源,因为只有 “11.11.11.11 “的用户能够访问它。

5. Whitelisting Using a Custom AuthenticationProvider

5.使用自定义AuthenticationProvider的白名单

Finally, we’ll see how to whitelist an IP range by building a custom AuthenticationProvider.

最后,我们将看到如何通过建立一个自定义的AuthenticationProvider来白名单一个IP范围。

We’ve seen how we can use hasIpAddress() to whitelist an IP range and how to mix it with other expressions. But sometimes, we need more customization.

我们已经看到我们如何使用hasIpAddress()来对一个IP范围进行白名单,以及如何将其与其他表达式混合。但有时,我们需要更多的定制

In the following example, we have multiple IP addresses whitelisted and only users from those IP addresses can log in to our system:

在下面的例子中,我们有多个IP地址被列入白名单,只有这些IP地址的用户可以登录我们的系统。

@Component
public class CustomIpAuthenticationProvider implements AuthenticationProvider {
    
   Set<String> whitelist = new HashSet<String>();

    public CustomIpAuthenticationProvider() {
        whitelist.add("11.11.11.11");
        whitelist.add("12.12.12.12");
    }

    @Override
    public Authentication authenticate(Authentication auth) throws AuthenticationException {
        WebAuthenticationDetails details = (WebAuthenticationDetails) auth.getDetails();
        String userIp = details.getRemoteAddress();
        if(! whitelist.contains(userIp)){
            throw new BadCredentialsException("Invalid IP Address");
        }
        //...
}

Now, we’ll use our CustomIpAuthenticationProvider in our security configuration:

现在,我们将在安全配置中使用我们的CustomIpAuthenticationProvider

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private CustomIpAuthenticationProvider authenticationProvider;

    @Bean
    public InMemoryUserDetailsManager userDetailsService(HttpSecurity http) throws Exception {
        UserDetails user = User.withUsername("john")
            .password("{noop}123")
            .authorities("ROLE_USER")
            .build();
        http.getSharedObject(AuthenticationManagerBuilder.class)
            .authenticationProvider(authenticationProvider)
            .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/login")
            .permitAll()
            .antMatchers("/foos/**")
            .access("isAuthenticated() and hasIpAddress('11.11.11.11')")
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .permitAll()
            .and()
            .csrf()
            .disable();
        return http.build();
    }
}

Here, we used the WebAuthenticationDetails getRemoteAddress() method to obtain a user’s IP address.

这里,我们使用WebAuthenticationDetails getRemoteAddress()方法来获取用户的IP地址。

As a result, only users with whitelisted IP will be able to access our system.

因此,只有拥有白名单IP的用户才能够访问我们的系统。

This is a basic implementation, but we can customize our AuthenticationProvider as much as we want using a user’s IP. For example, we can store the IP address with user details on signup and compare it during authentication in our AuthenticationProvider.

这是一个基本的实现,但是我们可以使用用户的IP来定制我们的AuthenticationProvider,只要我们想。例如,我们可以在注册时将IP地址与用户的详细信息存储在一起,并在我们的AuthenticationProvider.验证过程中进行比较。

6. Conclusion

6.结论

We learned how to whitelist an IP range in Spring Security using Java and XML configuration. We also learned how to whitelist an IP range by building a custom AuthenticationProvider.

我们学习了如何使用Java和XML配置在Spring Security中对IP范围进行白名单。我们还学习了如何通过建立一个自定义的AuthenticationProvider来白名单一个IP范围。

The full source code can be found over on GitHub.

完整的源代码可以在GitHub上找到over