1. 概述
在本教程中,我們將討論如何在 Spring Security 中使用白名單 IP 範圍。
我們將研究 Java 和 XML 配置。我們還將看到如何使用自定義 AuthenticationProvider 來白名單 IP 範圍。
2. Java 配置文件
首先,讓我們探索 Java 配置文件。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry.requestMatchers("/login").permitAll()
.requestMatchers("/foos/**")
.access(new WebExpressionAuthorizationManager("isAuthenticated() and hasIpAddress('11.11.11.11')")).anyRequest().authenticated())
.formLogin(AbstractAuthenticationFilterConfigurer::permitAll)
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
}
在此配置中,只有擁有 IP 地址“11.11.11.11”的用户才能訪問“/foos”資源。 並且,被白名單 IP 的用户無需在訪問“/foos/” URL 之前進行登錄。
如果我們希望擁有“11.11.11.11” IP 的用户首先進行登錄,則可以使用以下格式的表達式中的方法:
//...
.requestMatchers("/foos/**")
.access(new WebExpressionAuthorizationManager("isAuthenticated() and hasIpAddress('11.11.11.11')"))
//...
3. XML 配置
接下來,讓我們看看如何使用 XML 配置來白名單 IP 地址範圍:
我們將在這裏使用 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. 實時測試
現在,我們將進行一個簡單的實時測試,以確保一切正常工作。
首先,我們將確保任何用户在登錄後都可以訪問主頁:
@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"));
}
請注意,由於 IP 地址為“127.0.0.1”,我們無法訪問“/foos”資源,因為只有擁有“11.11.11.11”的 IP 地址的用户才能訪問它。
5. 使用自定義 AuthenticationProvider 進行白名單
最後,我們將看到如何通過構建一個自定義 AuthenticationProvider 來白名單一個 IP 地址範圍。
我們已經知道如何使用 hasIpAddress() 方法來白名單一個 IP 地址範圍,以及如何將其與其他表達式組合使用。但有時,我們需要更多的自定義。
在下面的示例中,我們白列了多個 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");
}
//...
}
現在,我們將使用我們的 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.authorizeHttpRequests(
authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry.requestMatchers("/login").permitAll()
.requestMatchers("/foos/**")
.access(new WebExpressionAuthorizationManager("isAuthenticated() and hasIpAddress('11.11.11.11')")).anyRequest().authenticated())
.formLogin(AbstractAuthenticationFilterConfigurer::permitAll)
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
}
這裏,我們使用了 WebAuthenticationDetails getRemoteAddress() 方法來獲取用户的 IP 地址。
作為結果,只有具有白列的 IP 地址的用户才能訪問我們的系統。
這是一個基本實現,但我們可以通過使用用户的 IP 地址來儘可能地自定義我們的 AuthenticationProvider。例如,我們可以將 IP 地址與用户詳細信息在註冊時存儲,並在我們的 AuthenticationProvider 中進行身份驗證期間進行比較。
6. 結論
我們學習瞭如何使用 Java 和 XML 配置在 Spring Security 中白名單 IP 範圍。我們還學習了通過構建自定義 AuthenticationProvider 來白名單 IP 範圍。