大佬教程收集整理的这篇文章主要介绍了如何对使用百里香的安全控制器进行单元测试(不获取TemplateProcessingException)?,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个解决方法,似乎可以完全解决spring-boot:1.1.4,spring- security:3.2.4和thymeleaf:2.1.3的问题(尽管有点麻烦)。
这是修改后的单元测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class AppControllersTest {
@autowired
public WebApplicationContext context;
@autowired
private FilterChainProxy springSecurityFilter;
private mockR_638_11845@vc mockR_638_11845@vc;
@Before
public voID setup() {
assertNotNull(context);
assertNotNull(springSecurityFilter);
// Process mock Annotations
mockitoAnnotations.initmocks(this);
// Setup Spring test in webapp-mode (same config as spring-boot)
this.mockR_638_11845@vc = mockR_638_11845@vcBuilders.webAppContextSetup(context)
.addFilters(springSecurityFilter)
.build();
context.getServletContext().setAttribute(
WebApplicationContext.ROOT_WEB_APPliCATION_COntexT_ATTRIBUTE, context);
}
...
这里的魔力是将强制为WebApplicationContext.ROOT_WEB_APPliCATION_COntexT_ATTRIBUTE
实际的Web应用程序上下文(我注入了该上下文)。这允许实际的sec:属性起作用,但是在我尝试设置权限以使用户登录未通过的第二次测试中(看起来用户仍然匿名)。
缺少了一些东西(我认为这是弹簧安全性工作方式上的空白),但是很幸运,它很容易解决(尽管有点麻烦)。请参阅此以获取有关该问题的更多详细信息:SpringTest&Security:如何模拟身份验证?
我需要添加一个为测试创建模拟会话的方法。此方法将设置安全性Principal
/ Authentication
并强制将/SecurityContext
插入httpSession
其中,然后可以将其添加到测试请求中(请参见下面的测试代码段和namedOauthprincipal
类示例)。
public mockhttpSession makeAuthSession(String username, String... roles) {
if (StringUtils.isEmpty(userName)) {
username = "azeckoski";
}
mockhttpSession session = new mockhttpSession();
session.setAttribute(httpSessionSecurityContextRepository.SPRING_Security_COntexT_KEY, SecurityContextHolder.getContext());
Collection<GrantedAuthority> authoritIEs = new HashSet<>();
if (roles != null && roles.length > 0) {
for (String role : roles) {
authoritIEs.add(new SimpleGrantedAuthority(rolE));
}
}
//Authentication authToken = new UsernamepasswordAuthenticationToken("azeckoski", "password", authoritIEs); // causes a NPE when it trIEs to access the Principal
Principal principal = new namedOauthprincipal(username, authoritIEs,
"key", "signature", "HMAC-SHA-1", "signaturebase", "token");
Authentication authToken = new UsernamepasswordAuthenticationToken(principal, null, authoritIEs);
SecurityContextHolder.getContext().setAuthentication(authToken);
return session;
}
创建类的类Principal
(通过ConsumerCredentials支持OAuth)。如果不使用OAuth,则可以跳过ConsumerCredentials部分,而只需实现Principal(但应返回GrantedAuthority的集合)。
public static class namedOauthprincipal extends ConsumerCredentials implements Principal {
public String name;
public Collection<GrantedAuthority> authoritIEs;
public namedOauthprincipal(String name, Collection<GrantedAuthority> authoritIEs, String consumerKey, String signature, String signatureMethod, String signatureBaseString, String token) {
super(consumerKey, signature, signatureMethod, signatureBaseString, token);
this.name = name;
this.authoritIEs = authoritIEs;
}
@OverrIDe
public String getname() {
return name;
}
public Collection<? extends GrantedAuthority> getAuthoritIEs() {
return authoritIEs;
}
}
然后像这样修改测试(以创建会话,然后在模拟请求上进行设置):
@Test
public voID testLoadRootWithAuth() throws Exception {
// Test basic home controller request with a session and logged in user
mockhttpSession session = makeAuthSession("azeckoski", "RolE_USER");
MvcResult result = this.mockR_638_11845@vc.perform(get("/").session(session))
.andExpect(status().isOk())
.andExpect(content().ContentTypeCompatibleWith(MediaType.TEXT_HTML))
.andReturn();
String content = result.getResponse().getContentAsString();
assertNotNull(content);
assertTrue(content.contains("Hello Spring Boot"));
}
我正在尝试使用spring security和一个简单的home(root)控制器在spring-
boot中运行单元测试,该控制器使用thymeleaf进行模板处理。我正在尝试编写一些单元测试,以验证我的安全权限是否正常工作,并且正确的数据是否已从我的模板(使用thymeleaf
spring安全集成)中隐藏或显示。当我运行该应用程序时,它本身可以正常运行。我只想验证它是否正在与一组集成测试一起使用。您可以在此处找到所有代码,但我还将在下面提供相关的摘要:
https://github.com/azeckoski/lti_starter
控制器真的很简单,除了呈现模板(在根处-即“ /”)外,什么也不做。
@Controller
public class HomeController extends BaseController {
@requestMapping(method = requestMethod.GET)
public String index(httpServletrequest req,Principal principal,Model model) {
log.info("HOME: " + req);
model.addAttribute("name","HOME");
return "home"; // name of the template
}
}
模板中有很多东西,但是测试的相关内容是:
<p>Hello Spring Boot User <span th:text="${usernamE}"/>! (<span th:text="${name}"/>)</p>
<div sec:authorize="hasRole('ROLE_USER')">
This content is only shown to users (ROLE_USER).
</div>
<div sec:authorize="isAnonymous()"><!-- only show this when user is NOT logged in -->
<h2>Form Login endpoint</h2>
...
</div>
最后是测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class AppControllersTest extends BaseApplicationTest {
@Autowired
WebApplicationContext wac;
@Autowired
private FilterChainProxy springSecurityFilter;
private mockR_638_11845@vc mockR_638_11845@vc;
@Before
public void setup() {
// Process mock Annotations
mockitoAnnotations.initmocks(this);
// Setup Spring test in webapp-mode (same config as spring-boot)
this.mockR_638_11845@vc = mockR_638_11845@vcBuilders.webAppContextSetup(waC)
.addFilter(springSecurityFilter,"/*")
.build();
}
@Test
public void testLoadRoot() throws Exception {
// Test basic home controller request
MvcResult result = this.mockR_638_11845@vc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
.andReturn();
String content = result.getResponse().getContentAsString();
assertNotNull(content);
assertTrue(content.contains("Hello Spring Boot"));
assertTrue(content.contains("Form Login endpoint"));
}
@Test
public void testLoadRootWithAuth() throws Exception {
Collection<GrantedAuthority> authorities = new HashSet<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication authToken = new UsernamepasswordAuthenticationToken("azeckoski","password",authorities);
SecurityContextHolder.getContext().setAuthentication(authToken);
// Test basic home controller request
MvcResult result = this.mockR_638_11845@vc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
.andReturn();
String content = result.getResponse().getContentAsString();
assertNotNull(content);
assertTrue(content.contains("Hello Spring Boot"));
assertTrue(content.contains("only shown to users (ROLE_USER)"));
}
}
我在以上测试中都得到的erorr是:
但是,只有在同时启用两个测试并且包括springSecurityFilter的情况下,这种情况才会发生。如果我禁用其中一项测试并删除springSecurityFilter代码(.addFilter(springSecurityFilter,"/*")
),则不会再出现该错误。我怀疑可能是某种原因弄乱了WebApplicationContext或使安全性处于某种故障状态,但是我不确定需要重置或更改的内容。
因此,如果我取出第二个测试并删除springSecurityFilter,则我的第一个测试仍将失败(尤其是该测试assertTrue(content.contains("Form
Login endpoint"))
),但是我不再遇到任何错误。当我查看生成的HTML时,没有看到使用该sec:authorize
属性的任何标签内容。
因此,我四处寻找并发现了一个建议,我需要添加一个建议springSecurityFilter
(我在上面的代码示例中已完成此建议),但是,一旦我这样做,我马上就会遇到失败(甚至没有得到解决)没有它就失败了)。关于什么原因导致该异常以及如何解决该异常的任何建议?
以上是大佬教程为你收集整理的如何对使用百里香的安全控制器进行单元测试(不获取TemplateProcessingException)?全部内容,希望文章能够帮你解决如何对使用百里香的安全控制器进行单元测试(不获取TemplateProcessingException)?所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。