@AuthenticationPrincipal object возвращает предыдущее значение, которое было сохранено в сеансе.@AuthenticationPrincipal object return session value
Весенний ботинок + весна безопасности oauth REST Server. https://github.com/legshort/spring-boot-sample
Эти два метода REST находятся в контроллере. Проблема в том, что последний аргумент userDetailsImpl в deleteUser() имеет то же значение, что и userDetailsImpl при updateUser(), когда я запускаю тестовый код.
@RequestMapping(method = RequestMethod.PUT, value = "https://stackoverflow.com/users/{userId}")
public ResponseEntity updateUser(@PathVariable Long userId,
@AuthenticationPrincipal UserDetailsImpl userDetailsImpl,
@Valid @RequestBody UserUpdateForm userUpdateForm,
BindingResult bindingResult) {
logger.info("UserUpdate: " + userUpdateForm);
User updatedUser = userService.updateUser(userUpdateForm
.createUser(userId));
return new ResponseEntity(updatedUser, HttpStatus.OK);
}
@RequestMapping(method = RequestMethod.DELETE, value = "https://stackoverflow.com/users/{userId}")
public ResponseEntity deleteUser(@PathVariable Long userId,
@AuthenticationPrincipal UserDetailsImpl userDetailsImpl) {
logger.info("UserDelete: " + userId);
User requestedUser = new User(userId);
userService.deleteUser(requestedUser);
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
Ниже контроллер код теста
Я не знаю, как, но второй запрос, который testDeleteUser() имеет значение сеанса, и это тот же пользователь, который использовал предыдущий тест. поэтому даже подумал в начале deleteUser() проверить токен доступа и загрузить права нового пользователя, но как-то реальное значение у userDetailsImpl имеет неправильный пользователь, созданный в начале testUpdateUser().
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).addFilters(filterChainProxy).build();
}
@Test
public void testUpdateUser() throws Exception {
User savedUser = signUpUser();
// @formatter:off
mockMvc.perform(
put("https://stackoverflow.com/users/" + savedUser.getId())
.header(HeaderUtil.AUTHORIZATION, getAuthorizationWithAccessToken())
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(UserUpdateFormFactory.newInstance())))
.andExpect(status().isOk())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(greaterThan(NumberUtils.INTEGER_ZERO))))
.andExpect(jsonPath("$.name", is(equalTo(StringUtil.NEW + UserFactory.NAME))));
// @formatter:on
}
@Test
public void testDeleteUser() throws Exception {
User savedUser = signUpUser();
String authorization = getAuthorizationWithAccessToken();
// @formatter:off
mockMvc.perform(
delete("https://stackoverflow.com/users/" + savedUser.getId())
.header(HeaderUtil.AUTHORIZATION, authorization)
.contentType(TestUtil.APPLICATION_JSON_UTF8))
.andDo(print())
.andExpect(status().isNoContent());
// @formatter:on
}
Это реализация UserDetailService, когда дело доходит до loadUserByUserName() для проверки маркеров доступа, он загружает надлежащий пользователь из базы данных и вернуть новый пользователь, который только что созданный в начале каждого метода испытаний (signUpUser()).
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String email)
throws UsernameNotFoundException {
User requestedUser = new User();
requestedUser.setEmail(email);
User savedUser = userService.findByEmail(requestedUser);
return new UserDetailsImpl(savedUser);
}
}
Я попытался отключить сеанс, который я потерпел неудачу, кажется мне хорошо с конфигурацией и тестовым кодом для меня. Есть ли хороший практический пример для весны-безопасности-ов?
ОБНОВЛЕНО
Насколько я понимаю, о mockMvc, оно сбрасывает все установки, и это создает довольно много нового Мок сервера каждый раз с методом нАлАдкА(). Следовательно, хранилище доступа к токенам должно быть очищено каждый раз, но в некотором смысле хранилище токенов поддерживает аутентифицированные токены.
Запросить токен доступа, запрошенный с помощью «/ oauth/token», который был пропущен во время теста, ниже описано, как вызывается InMemoryTokenStore.
Процесс испытания Вход
testUpdateUser() -> ПОСТ:/OAuth/маркер -> магазин маркер
маркер: 50b10897-9e15-4859-aeb0-43d0802ba42c
пользователь: id = 2testUpdateUser() -> PUT:/users/2 -> чтения маркеров
маркера: 50b10897-9e15-4859-aeb0-43d0802ba42c
пользователя: ID = 2testUpdateUserWithWrongUserId() -> GET:/OAuth/маркер -> магазин маркер
маркер: 50b10897-9e15- 4859-aeb0-43d0802ba42c -> уже существует в знак
пользователя: ID = 2 -> ID = 4: пользователь был обновлен с новым однимtestUpdateUserWithWrongUserId() -> PUT:/пользователей/0 -> прочитать токен
токен: 50b10897-9e15-4859-aeb0-43d0802ba42c
пользователь: ID = 2testDeleteUser() -> GET:/OAuth/маркер -> не хранить маркер, должен хранить маркер
testDeleteUser() -> DELETE:/Пользователи/5 - > прочитать маркер
маркер: 50b10897-9e15-4859-aeb0-43d0802ba42c
пользователя: ID = 2 -> пользователь должен был ID = 5, который был создан с userSignUp()
Вопросы
Как очистить InMemoryTokenStore каждый метод тестирования с помощью mockMvc?
Вы используете только один экземпляр wac (WebApplicationContext), поэтому главный хранитель там хранится между двумя испытаниями. Почему бы просто не устанавливать директиву явно в каждом тесте, например 'delete ("/users/"+ savedUser.getId()). Main (null)' ?? –
AuthenticationPrincipal предназначен для обеспечения безопасности SecurityContextHolder.getContext(). GetAuthentication(). GetPrincipal(), поэтому это ожидаемое поведение. Наверное, я изо всех сил пытаюсь понять, что вы хотите от своего кода. –
@RobWinch благодарит за ваш комментарий. Я хочу протестировать каждый метод с чистым статусом, чтобы я не хотел, чтобы в каждом методе тестирования не было сеанса или принципа, и я понимаю, что каждый метод тестирования должен быть чистым, чтобы предотвратить любое другое странное поведение. – Jun