У меня есть следующая конфигурация 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?