如何为@Service方法启用/禁用@EnableGlobalMethodSecurity以测试方案

时间:2017-09-14 19:55:02

标签: spring spring-security

我正在使用Spring FrameworkSpring Security

关于测试

对于@Controller 安全的一组测试类,使用.apply(springSecurity()@WithUserDetails(value="something")

@Before
public void setUp(){
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                             .apply(springSecurity())// <---
                             .build();
}

对于其他@Controller 的测试类集,没有 安全,因此.apply(springSecurity()) 和< / em> @WithUserDetails(value="something") 使用。

@Before
public void setUp(){
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)                              
                             .build();
} 

直到此处@Controller 没有安全性的所有工作都正常。

问题出在@Service,定义@EnableGlobalMethodSecurity@Service方法注释为@PreAuthorize("hasRole('ROLE_ADMIN')"),所有其他测试@Service安全 的类现在失败,但是:

org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: 
    An Authentication object was not found in the SecurityContext 

当然是因为@Test方法不使用@WithUserDetails(value="something")

因此,实际上.apply(springSecurity())完成了这项工作,但是通过MockMvcBuilders.webAppContextSetup(webApplicationContext)

来实现 Web 环境

但对于服务器端, security 需要

@Transactional
@RunWith(Parameterized.class)
@ContextConfiguration(classes={RootApplicationContext.class})
@ActiveProfiles(resolver=TestActiveProfilesResolver.class)
@TestExecutionListeners(listeners={LoggingTestExecutionListener.class}, mergeMode=MergeMode.MERGE_WITH_DEFAULTS)
public class PersonaServiceImplTest {

    private static final Logger logger = LoggerFactory.getLogger(PersonaServiceImplTest.class.getSimpleName());

    @ClassRule
    public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    @Autowired
    private Environment environment;

    ...

因此MockMvcBuilders.webAppContextSetup(webApplicationContext)无意义使用。解决这个问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:2)

您也可以使用@WithUserDetails@WithMockUser来测试方法的安全性。
为了测试有关方法安全性的测试,您需要在用于加载@EnableGlobalMethodSecurity的组件类中包括用ApplicationContext注释的类。

例如,如果配置类SecurityConfigEnableGlobalMethodSecurity注释

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig { }

服务MessageService具有使用@PreAuthorize的方法。

@Service
public class MessageService {
    public String getHelloMessage() {
        return "Hello!";
    }

    @PreAuthorize("hasRole('ADMIN')")
    public String getGoodbyeMessage() {
        return "Goodbye!";
    }
}

然后,您需要在MessageServiceTest中包括这两个类,并可以使用安全测试注释。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {SecurityConfig.class, MessageService.class})
public class MessageServiceTest {

    @Autowired
    MessageService messageService;

    @Test
    public void helloMessageReturnsHello() {
        assertThat(messageService.getHelloMessage()).isEqualTo("Hello!");
    }

    @Test(expected = AuthenticationCredentialsNotFoundException.class)
    public void goodbyeMessageWithoutUserThrowsException() {
        messageService.getGoodbyeMessage();
    }

    @WithMockUser(roles = "ADMIN")
    @Test
    public void goodbyeMessageWithAdminReturnsGoodbye() {
        assertThat(messageService.getGoodbyeMessage()).isEqualTo("Goodbye!");
    }
}