如何在Spring 5.7+中通过IP地址和凭据限制对资源的访问



既然Spring 5.6中的WebSecurityConfigurerAdapter已经被弃用,我们如何根据一组IP地址来限制对web应用资源的访问?我的目标是禁用默认的spring登录表单,但仍然只从一组给定的IP地址发送带有某些凭据的post请求到应用程序。

我一直在跟随Eugen在Baeldung的例子https://github.com/eugenp/tutorials/blob/4fa0844faf6f95bbde4a38d0b16cde066fd4d8af/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/ip/config/CustomIpAuthenticationProvider.java,这是为Spring 5.6编写的。我尝试升级到这里推荐的SecurityFilterChain: https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter。然后,我在使用SecurityFilterChain的类上使用@EnableWebSecurity时禁用了SecurityAutoConfiguration,但我无法让我的代码工作以阻止来自某些IP地址和给定用户的请求。

下面是我的代码。

主要应用
@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}

配置类
@Configuration
@EnableWebSecurity
public class SecurityConfig  {
@Bean
public SecurityFilterChain filterChain(HttpSecurity security) throws Exception {
security.csrf().disable().authorizeRequests().anyRequest().permitAll(); // Works for GET, POST, PUT, DELETE
security.authenticationProvider(new CustomIpAuthenticationProvider());
security.formLogin().disable();
return security.build();
}
}
@Bean
public InMemoryUserDetailsManager userDetailsService() {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
UserDetails user = User.withUsername("test_user")
.password(encoder.encode("password"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}

自定义认证提供程序

public class CustomIpAuthenticationProvider implements AuthenticationProvider {
Set<String> whitelist = new HashSet<>();
public CustomIpAuthenticationProvider() {
super();
whitelist.add("11.11.11.11");
//        whitelist.add("0.0.0.0");
//        whitelist.add("127.0.0.1");
}
@Override
public Authentication authenticate(Authentication auth){
WebAuthenticationDetails details = (WebAuthenticationDetails) auth.getDetails();
String userIp = details.getRemoteAddress();
System.out.println(userIp);
if (!whitelist.contains(userIp)) {
throw new BadCredentialsException("Invalid IP Address");
}
final String name = auth.getName();
final String password = auth.getCredentials().toString();
if (name.equals("test_user") && password.equals("password")) {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new UsernamePasswordAuthenticationToken(name, password, authorities);
}
else{
throw new BadCredentialsException("Invalid username or password");
}

}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}

单元测试到测试应用

@Test
public void givenUserWithWrongIPForbidden() {
Response response = RestAssured.given().auth().form("test_user", "password")
.get(base + "/login");
assertEquals(403, response.getStatusCode());
assertTrue(response.asString().contains("Forbidden"));
}

我也遇到了同样的问题。最后我改变了主意,用了滤镜。下面是一个例子

最新更新