如何为测试场景的 @Service 方法启用/禁用 @EnableGlobalMethodSecurity

Man*_*dan 3 spring spring-security

我正在与Spring FrameworkSpring Security

关于测试

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

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

对于没有安全性的其他测试类集,因此不使用@Controller .apply(springSecurity()) @WithUserDetails(value="something")

@Before
public void setUp(){
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)                              
                             .build();
} 
Run Code Online (Sandbox Code Playgroud)

到目前为止,所有关于@Controller 没有安全的情况都可以正常工作。

问题在于@Service,当@EnableGlobalMethodSecurity定义并且@Service方法用 注释时@PreAuthorize("hasRole('ROLE_ADMIN')"),不需要安全性的所有其他测试现在都会失败:@Service

org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: 
    An Authentication object was not found in the SecurityContext 
Run Code Online (Sandbox Code Playgroud)

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

因此,实际上.apply(springSecurity())可以完成这项工作,但它对于Web环境来说是通过MockMvcBuilders.webAppContextSetup(webApplicationContext)

但对于不需要安全性的服务器端,我有:

@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;

    ...
Run Code Online (Sandbox Code Playgroud)

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

Ele*_*ana 5

您也可以使用@WithUserDetails和来测试方法的安全性。 为了测试方法安全性,您需要在用于加载.@WithMockUser
@EnableGlobalMethodSecurityApplicationContext

例如,如果配置类SecurityConfig注释为EnableGlobalMethodSecurity

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig { }
Run Code Online (Sandbox Code Playgroud)

并且该服务MessageService有一个使用的方法@PreAuthorize

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

    @PreAuthorize("hasRole('ADMIN')")
    public String getGoodbyeMessage() {
        return "Goodbye!";
    }
}
Run Code Online (Sandbox Code Playgroud)

然后您需要将这两个类包含在 中,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!");
    }
}
Run Code Online (Sandbox Code Playgroud)