@sltay

Почему MockMVC игнорирует Security?

У меня есть следующая конфигурация Spring Security
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // для включения аннотации PreAuthorize
@SuppressWarnings("deprecation")
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    private final DetailsService userDetailsService;

    @Autowired
    public SpringSecurityConfig(DetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests()
                .antMatchers("/main").hasAnyRole("USER", "ADMIN") //указываем что в /main могут попасть только роли USER и ADMIN
                .antMatchers("/auth/login", "/auth/registration", "/error", "/api").permitAll() //в логин, регистарцию и ошибку могут попасть все
                .antMatchers("/css/**", "/js/**", "/images/**").permitAll()
                .and()
                .formLogin().loginPage("/auth/login") //указываем НЕ стандартную страницу логина, а кастомную
                .loginProcessingUrl("/processor_login") // action который перенаправляет нас при попытке залогиниться
                .defaultSuccessUrl("/", true) // если авторизовался
                .failureUrl("/auth/login?error") //если нет
                .and()
                .logout().logoutUrl("/logout").logoutSuccessUrl("/auth/login");//адрес для логаута
    }
    @Override
    public void configure(WebSecurity web) {
        web.ignoring()
                .antMatchers(
                        "/css/**", "/fonts/**",
                        "/images/**");
    }
    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

}


И контроллер + тест к нему

@SpringBootTest
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:/SQL/GetFriendsList.sql")
@Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, scripts = "classpath:/SQL/DeleteFriendsList.sql")
public class ControllersTest {
    @Autowired
    WebApplicationContext webApplicationContext;
    private MockMvc mock;

    @BeforeEach
    public void initMock(){
        mock = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

 @Test
    @WithMockUser(username = "testUsername", password = "123123")
    public void testFriends() throws Exception {
        mock.perform(get("/main/friends")).andExpect(status().isOk());
    }
    @Test
    public void testUnAuthError() throws Exception {
        mock.perform(get("/main/friends")).andExpect(status().is3xxRedirection());
    }


@GetMapping("/friends")
    public String getFriendsList(Model model) {
   Optional<User> user = userService.findUser(SecurityContextHolder.getContext().getAuthentication().getName());
    //some useful staff
}


Проблема в том, что исходя из конфига секьюрити, по адресу /main могут пройти лишь авторизованные пользователи, но во втором тесте (который без @WithMockUser) Mock-объект не попадает в редирект из-за ошибки, а валится об NullPointerException, пытаясь получить из контекста имя пользователя в первой строке метода контроллера. Как заставить MockMVC не игнорировать Security?
  • Вопрос задан
  • 116 просмотров
Решения вопроса 1
@sltay Автор вопроса
Оказалось, что я неправильно понял смысл .antMatchers("/main")
я подумал что все последующие запросы из /main (/main/friends например) будут тоже заблокированы, но нет, надо указывать все возможные запросы
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы