当前位置: 首页 > 知识库问答 >
问题:

如何单元测试spring security@preauthorize(hasRole)?

欧阳鸿德
2023-03-14

实际:200

我在MyController中有以下方法

@PreAuthorize(value = "hasRole('MY_ROLE') and hasRole('MY_SECOND_ROLE')")
@RequestMapping(value = "/myurl", method = RequestMethod.GET)
public String loadPage(Model model, Authentication authentication, HttpSession session) {
    ...stuff to do...
}

我创建了以下abstract-security-test.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <security:global-method-security secured-annotations="enabled" />

    <security:authentication-manager alias="authManager">
        <security:authentication-provider>
            <security:user-service>
                <security:user name="missingsecondrole" password="user" authorities="MY_ROLE" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>

</beans>
@ContextConfiguration("classpath:/spring/abstract-security-test.xml")
public class MyTest {
    private final MyController myController = new MyController();
    @Autowired
    private AuthenticationManager manager;

    @Test
    public void testValidUserWithInvalidRoleFails() throws Exception {
        MockMvc mockMvc = standaloneSetup(myController).setViewResolvers(viewResolver()).build();

        Authentication auth = login("missingsecondrole", "user");

        mockMvc.perform(get("/myurl")
            .session(session)
            .flashAttr(MODEL_ATTRIBUTE_NAME, new ModelMap())
            .principal(auth)).andExpect(status().isUnauthorized());
    }

    protected Authentication login(String name, String password) {
        Authentication auth = new UsernamePasswordAuthenticationToken(name, password);
        SecurityContextHolder.getContext().setAuthentication(manager.authenticate(auth));
        return auth;
    }

    private ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("WEB-INF/views");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

共有1个答案

章学义
2023-03-14

Spring Security 4提供了与mockmvc集成的全面支持。例如:

import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class SecurityMockMvcTests {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mvc;

    @Before
    public void setup() {
        mvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(springSecurity())
                .build();
    }

    @Test
    public void withUserRequestPostProcessor() {
        mvc
            .perform(get("/admin").with(user("admin").roles("USER","ADMIN")))
            ...
    }

    @WithMockUser(roles="ADMIN")
    @Test
    public void withMockUser() {
        mvc
            .perform(get("/admin"))
            ...
    }

 ...

问题所在

问题是设置SecurityContextHolder在此实例中不起作用。原因是,SecurityContextPersistenceFilter将使用SecurityContextRepository尝试从HttpServletRequest(默认情况下使用HttpSession)中找出SecurityContext。它找到(或未找到)的SecurityContext将覆盖您在SecurityContextHolder上设置的SecurityContext。

private SecurityContextRepository repository = 
      new HttpSessionSecurityContextRepository();

private void login(SecurityContext securityContext, HttpServletRequest request) {
    HttpServletResponse response = new MockHttpServletResponse();

    HttpRequestResponseHolder requestResponseHolder = 
          new HttpRequestResponseHolder(request, response);
    repository.loadContext(requestResponseHolder);

    request = requestResponseHolder.getRequest();
    response = requestResponseHolder.getResponse();

    repository.saveContext(securityContext, request, response);
}

让它变得更容易

如果您希望使与MockMvc的这种和其他安全相关的交互变得更容易,可以参考gs-spring-security-3.2示例应用程序。在该项目中,您将找到一些用于使用Spring Security和MockMvc的实用程序,称为SecurityRequestPostProcessors。要使用它们,您可以将前面提到的类复制到项目中。使用此实用程序将允许您编写类似于以下内容的内容:

RequestBuilder request = get("/110")
    .with(user(rob).roles("USER"));

mvc
    .perform(request)
    .andExpect(status().isUnAuthorized());

注意:不需要在请求上设置主体,因为只要用户通过身份验证,Spring Security就会为您建立主体。

您可能会问,为什么默认情况下不包含这一点。答案是,我们根本没有时间来完成3.2的时间线。示例中的所有代码都可以正常工作,但我们对命名约定以及如何集成以发布该代码的问题没有足够的信心。您可以跟踪SEC-2015,它将与Spring Security 4.0.0.M1一起发布。

更新

MockMvc实例还需要包含SpringSecurityFilterChain。为此,您可以使用以下方法:

@Autowired
private Filter springSecurityFilterChain;

@Test
public void testValidUserWithInvalidRoleFails() throws Exception {
    MockMvc mockMvc = standaloneSetup(myController)
        .addFilters(springSecurityFilterChain)
        .setViewResolvers(viewResolver())
        .build();
    ...
 类似资料:
  • 问题内容: 我已Spring Boot启用基本身份验证的应用程序。从数据库消耗。为了进行单元测试,我想对其进行模拟,以便从其他地方使用数据。 我该怎么做? 我的问题不是如何模拟自身,而是如何模拟使用它来通过基本身份验证测试Controller的方式。 以下是我的SpringSecurity配置: 总之,我怎么能嘲笑UserServiceDetails到SpringSecurity配置,所以我能单元

  • 本文向大家介绍SpringSecurity 测试实战,包括了SpringSecurity 测试实战的使用技巧和注意事项,需要的朋友参考一下 引言 试题管理系统的安全模块使用Spring Security,代码从原华软仓库移植,在移植的过程中,发现原测试编写的不好,遂在新系统中对安全模块测试进行了重构。 Spring 测试 添加@SpringBootTest注解,意为这是一个基于SpringBoot

  • 单元测试,对独立的代码功能片段,由编写代码的团队进行测试,也是一种编码,而非与之不同的一些事情。设计代码的一部分就是设计它该如何被测试。你应该写一个测试计划,即使它只是一句话。有时候测试很简单:“这个按钮看起来好吗?”,有时候它很复杂:“这个匹配算法可以精确地返回正确的匹配结果?”。 无论任何可能的时候,使用断言检查以及测试驱动。这不仅能尽早发现 bug,而且在之后也很有用,让你在其他方面担心的谜

  • Android Studio 1.1 添加了单元测试支持,详细请看 Unit testing support。本章的其余部分描述的是 “instrumentation tests”。利用 Instrumentation 测试框架可以构建独立的测试 APK 并运行在真实设备(或模拟器)中进行测试。

  • 英文原文:http://emberjs.com/guides/testing/unit/ 单元测试用于测试代码的一个小片段,确保其功能正常。与集成测试不同,单元测试被限定在一个范围内,并且不需要Ember应用运行。 全局 vs 模块 过去如果没有作为一个全局变量加载整个Ember应用,要对应用进行测试非常困难。通过使用模块(CommonJS,AMD等)来编写应用,可以只加载被测试的部分,而不用将其

  • 问题内容: 我有一个Java课。如何进行 单元测试? 就我而言,我有课做一个二进制和。它需要两个数组,将它们求和,然后返回一个新的二进制数组。 问题答案: 使用正确的输入定义正常情况下的预期和期望输出。 现在,通过声明一个类来实现测试,将其命名为任何东西(通常是类似TestAddingModule之类的东西),并向其添加testAdd方法(即,类似于下面的方法): 编写一个方法,并在其上方添加@T