我在控制器方法上有一个@PreAuthorize
批注,以使所有角色为“ ADMIN”的用户以及您自己的用户(也称为其身份验证主体)都可以使用它。
这与运行应用程序时的预期效果完全相同,但不适用于其测试:
控制器
@GetMapping("/{username}/role")
@PreAuthorize("hasRole('ADMIN') || #username == authentication.principal")
public String getOneUserRoleByUsername(final @PathVariable String username) { ... }
我在测试中使用@WithMockUser
,这对于测试“ ADMIN”角色非常有用,但不适用于用户名检查。
问题
响应是一个403
HTTP错误。
当我在测试中查看Spring Security的当前主体时,它会显示正确的用户名,因此
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
在测试中是“用户”,应该是这样。
在测试中,getAuthentication()
返回一个UsernamePasswordAuthenticationToken
,而正在运行的应用程序返回一个OAuth2Authentication
对象。它们具有不同的结构,其中OAuth对象具有userAuthentication
对象(其中包含principal
),而UsernamePasswordAuthenticationToken
直接具有principal
。
将authentication.principal
更改为authentication.principal.username
可以使测试工作,但不适用于正在运行的应用程序:
正在测试中,运行时会中断:
@PreAuthorize("hasRole('ADMIN') || #username == authentication.principal.username")
运行时正常运行,但无法通过测试:
@PreAuthorize("hasRole('ADMIN') || #username == authentication.principal")
将访问权限测试为“ ADMIN”-正常运行
@Test
@WithMockUser(username = "ABC", roles = {UserRole.ADMIN})
public void testGetOneUserRoleByUsername_asAdmin() throws Exception {
UserEntity userToSearch = new UserEntity("user", "password", UserRole.USER);
MvcResult result = mvc
.perform(get("/user/" + userToSearch.getUsername() + "/role"))
.andExpect(status().isOk())
.andReturn();
assertEquals(userToSearch.getRole(), result.getResponse().getContentAsString());
}
测试自己用户的访问权限-不起作用
@Test
@WithUserDetails("user") // Tried this one, too..
@WithMockUser("user")
// or @WithMockUser(username = "user")
public void testGetOneUserRoleByUsername_forOwnUser() throws Exception {
UserEntity userToSearch = new UserEntity("user", "password", UserRole.USER);
MvcResult result = mvc
.perform(get("/user/" + userToSearch.getUsername() + "/role"))
.andExpect(status().isOk())
.andReturn();
assertEquals(userToSearch.getRole(), result.getResponse().getContentAsString());
}