Ответ 1
UPDATE
Spring Безопасность 4 обеспечивает всестороннюю поддержку для интеграции с MockMvc. Например:
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class SecurityMockMvcTests {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
@Test
public void withUserRequestPostProcessor() {
mvc
.perform(get("/admin").with(user("admin").roles("USER","ADMIN")))
...
}
@WithMockUser(roles="ADMIN")
@Test
public void withMockUser() {
mvc
.perform(get("/admin"))
...
}
...
Проблема
Проблема заключается в том, что установка SecurityContextHolder не работает в этом случае. Причина в том, что SecurityContextPersistenceFilter будет использовать SecurityContextRepository, чтобы попытаться выяснить SecurityContext из HttpServletRequest (по умолчанию он использует HttpSession). SecurityContext, который находит (или не находит), переопределит SecurityContext, который вы установили в SecurityContextHolder.
Решение
Чтобы убедиться, что запрос аутентифицирован, вам необходимо связать свой SecurityContext с помощью SecurityContextRepository, который вы используете. По умолчанию используется HttpSessionSecurityContextRepository. Примерный метод, который позволит вам высмеивать вход пользователя пользователем:
private SecurityContextRepository repository =
new HttpSessionSecurityContextRepository();
private void login(SecurityContext securityContext, HttpServletRequest request) {
HttpServletResponse response = new MockHttpServletResponse();
HttpRequestResponseHolder requestResponseHolder =
new HttpRequestResponseHolder(request, response);
repository.loadContext(requestResponseHolder);
request = requestResponseHolder.getRequest();
response = requestResponseHolder.getResponse();
repository.saveContext(securityContext, request, response);
}
Детали использования этого могут быть немного неопределенными, поскольку вы можете не знать, как получить доступ к HttpServletRequest в MockMvc, но продолжайте читать, поскольку есть лучшее решение.
Упрощение
Если вы хотите сделать это и другие связанные с безопасностью взаимодействия с MockMvc проще, вы можете обратиться к примерному приложению gs- spring -security-3.2. В рамках проекта вы найдете некоторые утилиты для работы с Spring Security и MockMvc под названием SecurityRequestPostProcessors. Чтобы использовать их, вы можете скопировать этот ранее упомянутый класс в свой проект. Использование этой утилиты позволит вам написать что-то вроде этого:
RequestBuilder request = get("/110")
.with(user(rob).roles("USER"));
mvc
.perform(request)
.andExpect(status().isUnAuthorized());
ПРИМЕЧАНИЕ. Нет необходимости устанавливать принципала в запросе как Spring Безопасность устанавливает для вас Принципала, если пользователь аутентифицирован.
Вы можете найти дополнительные примеры в SecurityTests. Этот проект также поможет в других интеграциях между MockMvc и Spring Security (т.е. Настройке запроса с помощью токена CSRF при выполнении POST).
Не включено по умолчанию?
Вы можете спросить, почему это не включено по умолчанию. Ответ заключается в том, что у нас просто не было времени на 3.2-временную шкалу. Весь код в образце будет работать нормально, но мы не были достаточно уверены в соглашениях об именах и точно как он интегрировался для его выпуска. Вы можете отслеживать SEC-2015, который планируется выпустить с помощью Spring Security 4.0.0.M1.
Обновление
В вашем экземпляре MockMvc также должен быть файл springSecurityFilterChain. Для этого вы можете использовать следующее:
@Autowired
private Filter springSecurityFilterChain;
@Test
public void testValidUserWithInvalidRoleFails() throws Exception {
MockMvc mockMvc = standaloneSetup(myController)
.addFilters(springSecurityFilterChain)
.setViewResolvers(viewResolver())
.build();
...
Чтобы работать @Autowired
, вам необходимо включить свою конфигурацию безопасности, которая делает springSecurityFilterChain в вашем @ContextConfiguration
. Для вашей текущей настройки это означает, что "classpath:/spring/abstract-security-test.xml" должен содержать вашу часть <http ..>
вашей конфигурации безопасности (и все зависимые beans). Кроме того, вы можете включить второй файл в @ContextConfiguration
, у которого есть ваша <http ..>
часть вашей конфигурации безопасности (и все зависимые beans).