12. Spring MVC Test Integration(Spring MVC测试集成)
Spring Security提供了与Spring MVC测试的全面集成。
12.1 Setting Up MockMvc and Spring Security(设置MockMvc和Spring安全性)
Spring MVC Test提供了一个方便的接口,称为RequestPostProcessor(请求后处理器),可以用来修改请求。Spring Security提供了许多RequestPostProcessor实现,使得测试更加容易。为了使用Spring Security的RequestPostProcessor实现,请确保使用以下静态导入:
importstaticorg.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
12.2.1 Testing with CSRF Protection
当测试任何不安全的HTTP方法并使用Spring Security的CSRF保护时,您必须确保在请求中包含有效的CSRF令牌。使用以下命令将有效的CSRF令牌指定为请求参数:
mvc.perform(post("/").with(csrf()))
1、如果您愿意,可以在标题中包含CSRF令牌:
mvc.perform(post("/").with(csrf().asHeader()))
2、您还可以使用以下方法测试提供无效的CSRF令牌:
mvc.perform(post("/").with(csrf().useInvalidToken()))
12.2.2 Running a Test as a User in Spring MVC Test 在Spring MVC测试中以User运行测试
通常希望以特定用户的身份运行测试。有两种简单的方式来填充用户:见12.2.3
12.2.3 Running as a User in Spring MVC Test with RequestPostProcessor
在带有请求后处理器(RequestPostProcessor)的Spring MVC测试中以User身份运行。
有许多选项可以将用户与当前的HttpServletRequest相关联。例如,以下将作为用户名为“user”、密码为“password”、角色为“ROLE_USER”的用户(不需要存在)运行:
mvc.perform(get("/").with(user("user")))
支持通过将用户与HttpServletRequest相关联来工作。要将请求与安全上下文持有者(SecurityContextHolder )相关联,您需要确保安全上下文持久性过滤器(SecurityContextPersistenceFilter )与MockMvc实例相关联。有几种方法可以做到这一点:
调用应用程序(springSecurity())
将Spring Security的FilterChainProxy添加到MockMvc
使用MockMvcbuilders . standalone setup时,向MockMVc实例手动添加securityContextPersistenceFilter可能有意义
1、您可以轻松进行自定义。例如,以下将作为用户名为“admin”、密码为“pass”、角色为“ROLE_USER”和“ROLE_ADMIN”的用户(不需要存在)运行。
mvc.perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN")))
2、如果您有一个想要使用的自定义用户详细信息,您也可以轻松地指定它。例如,以下将使用指定的用户详细信息(不需要存在)来运行具有指定用户详细信息主体的用户名密码身份验证令牌(UsernamePasswordAuthenticationToken ):
mvc.perform(get("/").with(user(userDetails)))
3、您可以使用以下方式作为匿名用户运行:
mvc.perform(get("/").with(anonymous()))
如果您使用默认用户运行,并且希望以匿名用户身份执行一些请求,这一点尤其有用。
4、如果您想要自定义身份验证(不需要存在),可以使用以下方法:
mvc.perform(get("/").with(authentication(authentication)))
5、您甚至可以使用以下方式自定义安全性上下文:
mvc.perform(get("/").with(securityContext(securityContext)))
6、通过使用MockMvcBuilders的默认请求,我们还可以确保作为每个请求的特定用户运行。例如,以下将作为用户名为“admin”、密码为“password”、角色为“ROLE_ADMIN”的用户(不需要存在)运行:
mvc = MockMvcBuilders.webAppContextSetup(context).
defaultRequest(get("/").
with(user("user").
roles("ADMIN"))).
apply(springSecurity()).
build();
7、如果您发现您在许多测试中使用同一个用户,建议您将该用户移至某个方法。例如,您可以在自己的名为customsecuritymockmvCrequestPostprocessors的类中指定以下内容:
publicstaticRequestPostProcessor rob() {returnuser("rob").roles("ADMIN");}
现在,您可以在securitymockmvrequestPostprocessors上执行静态导入,并在测试中使用它:
importstaticsample.CustomSecurityMockMvcRequestPostProcessors.*;...
mvc.perform(get("/").with(rob()))
Running as a User in Spring MVC Test with Annotations(通过注释测试springMVC)
作为使用请求后处理器创建用户的替代方法,您可以使用第11章“测试方法安全性”中描述的注释。例如,下面将使用用户名为“user”、密码为“password”、角色为“ROLE_USER”的用户运行测试:
或者,下面将使用用户名为“user”、密码为“password”、角色为“ROLE_ADMIN”的用户运行测试:
12.2.4 Testing HTTP Basic Authentication(测试HTTP基本身份验证)
虽然一直以来都有可能通过HTTP Basic进行身份验证,但是记住标头名称、格式和编码值有点乏味。现在,这可以使用Spring Security的httpBasic RequestPostProcessor来完成。例如,下面的代码片段:
mvc.perform(get("/").with(httpBasic("user","password")))
将通过确保在HTTP请求中填充以下标头,尝试使用HTTP Basic验证用户名为“user”且密码为“password”的用户:
Authorization: Basic dXNlcjpwYXNzd29yZA==
12.3 Security Mock Mvc Request Builders(安全模拟Mvc请求生成器)
Spring MVC测试还提供了一个RequestBuilder接口,可以用来创建测试中使用的MockHttpServletRequest。Spring Security提供了一些RequestBuilder实现,可以用来简化测试。为了使用Spring Security的RequestBuilder实现,请确保使用以下静态导入:
importstaticorg.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*;
12.3.1 Testing Form Based Authentication(基于测试表单的身份验证)
使用Spring Security的测试支持,您可以轻松地创建一个基于表单的身份验证的测试请求。例如,以下用户将使用用户名“user”、密码“password”和有效的CSRF令牌提交“POST to”/“log in”:
mvc.perform(formLogin())
定制请求很容易。例如,下面将提交一个POST到“/auth”,用户名为“admin”,密码为“pass”,有效的CSRF令牌:
mvc.perform(formLogin("/auth").user("admin").password("pass"))
我们还可以自定义用户名和密码所包含的参数名称。例如,这是上面修改过的请求,在HTTP参数“u”中包含用户名,在HTTP参数“p”中包含密码。
mvc.perform(formLogin("/auth").user("u","admin").password("p","pass"))
12.3.2 Testing Logout(测试登出)
虽然使用标准的Spring MVC测试相当简单,但是您可以使用Spring Security的测试支持来使测试注销更加容易。例如,下面将使用有效的CSRF令牌向“/logout”提交post请求:
mvc.perform(logout())
您还可以自定义要请求的URL路径。例如,下面的代码片段将使用有效的CSRF令牌向“/signout”提交一个POST:
mvc.perform(logout("/signout"))
12.4 SecurityMockMvcResultMatchers(安全模拟Mvc结果匹配器)
有时需要对请求做出各种与安全相关的断言。为了适应这种需求,Spring安全测试支持实现了Spring MVC测试的结果匹配器接口。为了使用Spring Security的ResultMatcher实现,请确保使用以下静态导入:
importstaticorg.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*;
12.4.1 Unauthenticated Assertion(未经验证的断言)
有时,断言没有经过身份验证的用户与MockMvc调用的结果相关联可能是有价值的。例如,您可能想要测试提交无效的用户名和密码,并验证没有用户经过身份验证。利用Spring Security的测试支持,您可以很容易地做到这一点,方法如下:
mvc.perform(formLogin().password("invalid")).andExpect(unauthenticated());
12.4.2 Authenticated Assertion(认证断言)
通常情况下,我们必须断言已经过身份验证的用户存在。例如,我们可能想要验证我们是否成功通过了身份验证。我们可以通过以下代码片段来验证基于表单的登录是否成功:
mvc
.perform(formLogin())
.andExpect(authenticated());
如果我们想要断言用户的角色,我们可以细化我们之前的代码,如下所示:
mvc.perform(formLogin().user("admin")).andExpect(authenticated().withRoles("USER","ADMIN"));
或者,我们可以验证用户名:
mvc.perform(formLogin().user("admin")).andExpect(authenticated().withUsername("admin"));
我们还可以将这些断言结合起来:
mvc.perform(formLogin().user("admin").roles("USER","ADMIN")).andExpect(authenticated().withUsername("admin"));