我正在使用:
request.IsUserInRole("ADMIN")
在我的一个控制器中确定对请求的响应。我试着在测试中模仿这个请求,比如:
@Mock
private HttpServletRequest httpRequest;
并使用Springs注释@WithMockUser
:
@Test
@WithMockUser(roles={"USER, ADMIN"})
public void getAccountsTest() throws Exception {...}
两者都不起作用。
问题1:如何在JUnit测试中模拟request.IsUserInRole("ADMIN")
?
问题2:@WithMockUser
对请求和request.IsUserInRole("ADMIN")
有什么影响?
感谢
----编辑----
"不起作用"意味着我有一个测试方法:
@Test
@WithMockUser(username = "user", roles={"USER"})
public void getAccountsReturnForbiddenTest() throws Exception {
mockMvc.perform(get("/accounts/"))
.andExpect(status().isForbidden());
}
应该返回403,由于控制器的原因不允许:
@RequestMapping(method=RequestMethod.GET)
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<PagedResources<AccountResource>> getAccounts(...){...}
但是请求返回200,好的。
我使用的是Spring Boot 1.4.1。
----编辑2-
我的JUnit测试类:
@Transactional
@ContextConfiguration
public class AccountControllerTestDoc extends AbstractControllerTest {
@InjectMocks
private AccountController accountController;
@Mock
private AccountService accountService;
private String uriBase = "";
@Before
public void setup() {
// Initialize Mockito annotated components
MockitoAnnotations.initMocks(this);
// Prepare the Spring MVC Mock components for standalone testing
setup(accountController);
}
@Test
@WithMockUser(username = "user", roles={"USER"})
public void getAccountsReturnForbiddenTest() throws Exception {
String uri = uriBase + "/accounts";
mockMvc.perform(get(uri))
.andExpect(status().isForbidden());
}
}
使用AbstractControllerTest:
@WebAppConfiguration
public abstract class AbstractControllerTest extends AbstractTest {
protected MockMvc mockMvc;
@Autowired
protected WebApplicationContext wac;
protected void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
protected void setup(BaseController controller) {
mockMvc = MockMvcBuilders.standaloneSetup(controller))
.build();
}
}
和AbstractTest:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public abstract class AbstractTest {
protected Logger LOG = LoggerFactory.getLogger(this.getClass());
}
----解决方案----
MockMvc
standaloneSetup
不知道web应用程序上下文,因此不知道安全过滤器链。必须使用web应用程序上下文和安全过滤器链设置MockMvc
,才能测试安全方面。
这是我现在正在工作的解决方案,我编辑了AbstractControllerTest:
@WebAppConfiguration
public abstract class AbstractControllerTest extends AbstractTest {
protected MockMvc mockMvc;
@Autowired
protected WebApplicationContext wac;
@Autowired
FilterChainProxy springSecurityFilterChain;
protected void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(wac)
.addFilters(springSecurityFilterChain)
.build();
}
protected void setup(BaseController controller) {
mockMvc = MockMvcBuilders.standaloneSetup(controller))
.build();
}
}
您应该在创建MockMvc
时添加springSecurityFilterChain
protected MockMvc mockMvc;
@Autowired
protected WebApplicationContext wac;
@Autowired
protected Filter springSecurityFilterChain;
protected void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(wac)
.addFilters(springSecurityFilterChain)
.build();
}
@Test
@WithMockUser(username="xx", roles= {"TIMESHEET"})
public void createNew() throws FailingHttpStatusCodeException, MalformedURLException, IOException {
assertTrue(Constants.isUserInRole("ROLE_TIMESHEET"), "user not in correct role");
其中Constants.isUserInRole定义为
public static Boolean isUserInRole(String role) {
return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()).map(x->x.getAuthorities()).get()
.stream().anyMatch(x->x.getAuthority().equals(role));
}
然后使用此isUserInRole而不是request.isUserInRole.