Spring Security 實現IP白名單機制

Spring Security 實現IP白名單機制

本文討論如何在Spring Security 中實現IP白名單機制。先看看默認實現機制,同時也討論自定義AuthenticationProvider實現更加靈活的應用。

1. 默認實現

首先我們看下Java配置。使用hasIpAddress() 定義允許特定ip地址的用戶訪問特定資源。請看下面使用hasIpAddress()的配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .antMatchers("/login").permitAll()
          .antMatchers("/foos/**").hasIpAddress("11.11.11.11")
          .anyRequest().authenticated()
          .and()
          .formLogin().permitAll()
          .and()
          .csrf().disable();
    }
 
    // ...
 
}

上面配置只有"11.11.11.11"地址的用戶可以訪問“/foos”的資源。使用白名單IP的用戶在訪問“/foos/”URL之前也不需要登錄。如果需要先登錄,那麼配置表達式如下:

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

1.1. 測試

下面進行簡單的測試,確保如預期的工作。首先確保任何用戶登錄後能訪問主頁:

@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"));
}

接下來,我們確保即使已認證用戶不能訪問“/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"));
}

注意,我們不能從本地主機“127.0.0.1”訪問“/foos”資源,只有具有“11.11.11.11”的用戶才能訪問它。

2. 自定義AuthenticationProvider實現

接下來看看如何通過自定義AuthenticationProvider實現更加靈活的限制。
我們已經看到hasIpAddress()方法及混合其它表達式實現,但有時需要更加定製化。
下面的示例我們有多個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");
        }
        //...
}

現在我們在Spring Security配置中使用CustomIpAuthenticationProvider:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Autowired
    private CustomIpAuthenticationProvider authenticationProvider;
 
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.authenticationProvider(authenticationProvider);
    }
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .antMatchers("/login").permitAll()
          .anyRequest().authenticated()
          .and().formLogin().permitAll()
          .and().csrf().disable();
    }
 
}

這裏使用WebAuthenticationDetails.getRemoteAddress() 方法獲取用戶IP地址。因此只有在白名單列表中的用戶可以訪問系統資源。

這僅僅是個基本實現,但我們可以自定義更強大的AuthenticationProvider。例如,我們可以在註冊時存儲帶有用戶詳細信息的IP地址,並在驗證期間在AuthenticationProvider中對其進行比較。

3. 總結

本文學習了兩種方法實現IP白名單機制,尤其是自定義AuthenticationProvider機制功能很強大。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章