Модульное тестирование с Spring Security - PullRequest
123 голосов
/ 11 декабря 2008

Моя компания оценивает Spring MVC, чтобы определить, следует ли нам использовать его в одном из наших следующих проектов. Пока что мне нравится то, что я видел, и сейчас я смотрю на модуль Spring Security, чтобы определить, можем ли мы / должны это использовать.

Наши требования безопасности довольно просты; пользователь просто должен иметь возможность предоставить имя пользователя и пароль для доступа к определенным частям сайта (например, для получения информации о своей учетной записи); и на сайте есть несколько страниц (часто задаваемые вопросы, поддержка и т. д.), где анонимному пользователю должен быть предоставлен доступ.

В создаваемом мной прототипе я хранил объект "LoginCredentials" (который просто содержит имя пользователя и пароль) в сеансе для аутентифицированного пользователя; некоторые контроллеры проверяют, находится ли этот объект в сеансе, например, для получения ссылки на имя пользователя, вошедшего в систему. Вместо этого я собираюсь заменить эту доморощенную логику на Spring Security, что было бы неплохо, если бы вы удалили «как мы отслеживаем зарегистрированных пользователей?». и "как мы аутентифицируем пользователей?" из моего контроллера / бизнес-код.

Похоже, что Spring Security предоставляет (для каждого потока) "контекстный" объект, чтобы иметь возможность доступа к имени пользователя / основной информации из любой точки вашего приложения ...

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

... что выглядит очень не по-весеннему, так как этот объект в некотором смысле является (глобальным) синглтоном.

У меня такой вопрос: если это стандартный способ доступа к информации о прошедшем проверку подлинности пользователя в Spring Security, каков приемлемый способ внедрения объекта Authentication в SecurityContext, чтобы он был доступен для моих модульных тестов, когда модуль тесты требуют аутентифицированного пользователя?

Нужно ли подключать это в методе инициализации каждого теста?

protected void setUp() throws Exception {
    ...
    SecurityContextHolder.getContext().setAuthentication(
        new UsernamePasswordAuthenticationToken(testUser.getLogin(), testUser.getPassword()));
    ...
}

Это кажется слишком многословным. Есть ли более простой способ?

Сам объект SecurityContextHolder выглядит очень не по-весеннему ...

Ответы [ 11 ]

0 голосов
/ 11 июня 2014

После довольно большой работы я смог воспроизвести желаемое поведение. Я эмулировал логин через MockMvc. Это слишком тяжело для большинства модульных тестов, но полезно для интеграционных тестов.

Конечно, я хочу увидеть новые функции Spring Security 4.0, которые облегчат наше тестирование.

package [myPackage]

import static org.junit.Assert.*;

import javax.inject.Inject;
import javax.servlet.http.HttpSession;

import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

@ContextConfiguration(locations={[my config file locations]})
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public static class getUserConfigurationTester{

    private MockMvc mockMvc;

    @Autowired
    private FilterChainProxy springSecurityFilterChain;

    @Autowired
    private MockHttpServletRequest request;

    @Autowired
    private WebApplicationContext webappContext;

    @Before  
    public void init() {  
        mockMvc = MockMvcBuilders.webAppContextSetup(webappContext)
                    .addFilters(springSecurityFilterChain)
                    .build();
    }  


    @Test
    public void testTwoReads() throws Exception{                        

    HttpSession session  = mockMvc.perform(post("/j_spring_security_check")
                        .param("j_username", "admin_001")
                        .param("j_password", "secret007"))
                        .andDo(print())
                        .andExpect(status().isMovedTemporarily())
                        .andExpect(redirectedUrl("/index"))
                        .andReturn()
                        .getRequest()
                        .getSession();

    request.setSession(session);

    SecurityContext securityContext = (SecurityContext)   session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);

    SecurityContextHolder.setContext(securityContext);

        // Your test goes here. User is logged with 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...