我有一个只能从特定IP地址调用的Web应用程序。除此之外,不需要认证或授权;如果您来自正确的IP,您可以看到所有内容。
为此,搜索StackOverflow和其他地方,我发现了一些建议,用于在Spring Security中按IP地址过滤请求。他们都采用了这种形式(使用java配置扩展WebSecurityConfigurerAdapter):
http.authorizeRequests().anyRequest().access("hasIpAddress('127.0.0.1/0')");
然而,这对我来说没有用;它从不拒绝任何请求,无论我发出请求的IP地址。相反,我使用这样的自定义过滤器实现了我的IP过滤:
@Configuration
@EnableWebSecurity
@PropertySource("classpath:config.properties")
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
@Autowired
private Environment env;
@Override
protected void configure(HttpSecurity http) throws Exception {
String ipRange = env.getRequiredProperty("trusted_ips");
logger.info("@@@@@ SETTING UP SECURITY CONFIGURATION @@@@@@@@@@@@@");
logger.info("@@ trusted_ips: " + ipRange);
logger.info("@@@@@ SETTING UP SECURITY CONFIGURATION - END @@@@@@@@@@@@@");
http.addFilterBefore(new IPSecurityFilter(ipRange), J2eePreAuthenticatedProcessingFilter.class)
.authorizeRequests().antMatchers("/**").permitAll();
}
}
我的IPSecurityFilter:
public class IPSecurityFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(IPSecurityFilter.class);
private String[] ipAddresses;
public IPSecurityFilter(String strIPAddresses) {
logger.info("@@@@ Our IP Address whitelist: " + strIPAddresses);
this.ipAddresses = strIPAddresses.split(",");
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
logger.info("Checking whether request should be allowed: " + request.getRequestURI());
logger.info("@@@ Request is coming from IP address: " + request.getRemoteAddr());
for (String ipAddress : ipAddresses) {
if (ipAddress.equals(request.getRemoteAddr())) {
logger.info("@@@ Allowing request from ip address: " + request.getRemoteAddr());
return; // We accept requests from this IP address
}
}
// The remote IP address isn't on our white list; throw an exception
throw new AccessDeniedException("Access has been denied for your IP address: " + request.getRemoteAddr());
}
}
这似乎有效,因为请求被拒绝,如果它来自我的白名单上的IP地址。
但是,使用此配置,我的单元(使用MockMvc)测试失败;它以一种我从未预料到的方式失败。当单元测试运行时,它似乎正确使用Spring Security配置,并且请求通过安全测试(IP白名单包括127.0.0.1,并且根据运行测试时生成的日志,请求即将到来来自那个IP)。但是,请求似乎永远不会路由到我的控制器。
这是我的测试:
@RunWith(SpringRunner.class)
@WebMvcTest()
//@WebMvcTest(value = HandlerController.class)
@AutoConfigureMockMvc
@Import(SecurityConfig.class)
public class HandlerControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void getIndex() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().json("{\"services\":[\"OutboundMessageService\"]}", true));
}
}
最后,这是我的控制器(请忽略我生成JSON返回值的愚蠢方式,它还处于开发的早期阶段):
@RestController
public class HandlerController {
private static final Logger logger = LoggerFactory.getLogger(HandlerController.class);
@RequestMapping("/")
public String index() {
logger.info("### handling a request for / ###");
return "{\"services\":[\"OutboundMessageService\"]}";
}
}
以下是测试结果:
2017-11-14 08:29:12.151 INFO 25412 --- [ main] c.z.s.controllers.HandlerControllerTest : Starting HandlerControllerTest on 597NLL1 with PID 25412 (started by User in C:\Development\KnowledgeBin\NewArchitecture\OutboundMessageHandler)
2017-11-14 08:29:12.152 INFO 25412 --- [ main] c.z.s.controllers.HandlerControllerTest : No active profile set, falling back to default profiles: default
2017-11-14 08:29:12.178 INFO 25412 --- [ main] o.s.w.c.s.GenericWebApplicationContext : Refreshing org.springframework.web.context.support.GenericWebApplicationContext@209da20d: startup date [Tue Nov 14 08:29:12 MST 2017]; root of context hierarchy
2017-11-14 08:29:13.883 INFO 25412 --- [ main] b.a.s.AuthenticationManagerConfiguration :
Using default security password: 56e3fab8-f7fb-4fbd-b2d2-e37eae8cef5e
2017-11-14 08:29:13.962 INFO 25412 --- [ main] c.z.services.security.IPSecurityFilter : @@@@ Our IP Address whitelist: 122.22.22.22,127.0.0.1
2017-11-14 08:29:14.086 INFO 25412 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3f4f9acd, org.springframework.security.web.context.SecurityContextPersistenceFilter@470a9030, org.springframework.security.web.header.HeaderWriterFilter@60c16548, org.springframework.security.web.csrf.CsrfFilter@435ce306, org.springframework.security.web.authentication.logout.LogoutFilter@607b2792, com.zpaper.services.security.IPSecurityFilter@46baf579, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@27494e46, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@36453307, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@4bf324f9, org.springframework.security.web.session.SessionManagementFilter@452c8a40, org.springframework.security.web.access.ExceptionTranslationFilter@39ce27f2, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@5767b2af]
2017-11-14 08:29:14.183 INFO 25412 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.zpaper.services.controllers.HandlerController.index()
2017-11-14 08:29:14.184 INFO 25412 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/OutboundMessageService]}" onto public java.lang.String com.zpaper.services.controllers.HandlerController.outboundMessage()
2017-11-14 08:29:14.189 INFO 25412 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-11-14 08:29:14.190 INFO 25412 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-11-14 08:29:14.243 INFO 25412 --- [ main] c.z.s.config.HandlerWebConfiguration : #### My Configuration handler was called ####
2017-11-14 08:29:14.253 INFO 25412 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler]
2017-11-14 08:29:14.313 INFO 25412 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.web.context.support.GenericWebApplicationContext@209da20d: startup date [Tue Nov 14 08:29:12 MST 2017]; root of context hierarchy
2017-11-14 08:29:14.784 INFO 25412 --- [ main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring FrameworkServlet ''
2017-11-14 08:29:14.784 INFO 25412 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : FrameworkServlet '': initialization started
2017-11-14 08:29:14.805 INFO 25412 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : FrameworkServlet '': initialization completed in 21 ms
2017-11-14 08:29:14.897 INFO 25412 --- [ main] c.z.s.controllers.HandlerControllerTest : Started HandlerControllerTest in 3.095 seconds (JVM running for 3.995)
2017-11-14 08:29:14.981 INFO 25412 --- [ main] c.z.services.security.IPSecurityFilter : Checking whether request should be allowed: /
2017-11-14 08:29:14.981 INFO 25412 --- [ main] c.z.services.security.IPSecurityFilter : @@@ Request is coming from IP address: 127.0.0.1
2017-11-14 08:29:14.981 INFO 25412 --- [ main] c.z.services.security.IPSecurityFilter : @@@ Allowing request from ip address: 127.0.0.1
MockHttpServletRequest:
HTTP Method = GET
Request URI = /
Parameters = {}
Headers = {Accept=[application/json]}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY]}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.363 sec <<< FAILURE! - in com.zpaper.services.controllers.HandlerControllerTest
getIndex(com.zpaper.services.controllers.HandlerControllerTest) Time elapsed: 0.12 sec <<< ERROR!
org.json.JSONException: Unparsable JSON string:
at org.skyscreamer.jsonassert.JSONParser.parseJSON(JSONParser.java:42)
从日志消息中可以看出,正在调用IP过滤器并允许请求继续。但是,我的处理程序中发出的调试字符串无处可见,返回正文为空。谁能告诉我为什么我的安全过滤器会阻止MockMvc将其请求成功路由到我的控制器?
最后注意:如果我使用http.authorizeRequests()。anyRequest()。access(&#34; hasIpAddress(&#39; 127.0.0.1/0&#39;)&# 34);我首先列出的配置或通过删除我的SecurityConfig类完全摆脱Spring Security,请求被成功路由到我的处理程序。
答案 0 :(得分:4)
我想出了如何让测试工作。我无法找到一篇回答我的问题的文章,但是通过从多篇博文中提出不同的建议,我想出了这个对我有用的文章:
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HandlerController.class)
public class HandlerControllerTest {
private MockMvc mvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Before
public void setUp() {
// mvc = MockMvcBuilders.standaloneSetup(new HandlerController()).build();
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void getIndex() throws Exception {
mvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().json("{\"services\":[\"OutboundMessageService\"]}", true));
}
@Test
public void getMessageService() throws Exception {
mvc.perform(get("/OutboundMessageService").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().json("{\"status\": \"SUCCESS\"}", true));
}
}
正如您所看到的,我不再自动连接MockMvc对象并允许它自动设置,而是在setUp()方法中自行设置它。 setUp()方法中的注释掉的行也可以成功测试我的控制器,但它不会通过我的Spring Security IP地址过滤器路由请求。我将其保留下来,以便不需要测试Spring Security的用户可以看到另一种设置MockMvc对象的方法。未注释的行设置MockMvc对象,以便它通过安全过滤器和我的控制器运行请求。