У меня есть примечание @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());
}