【问题标题】:Spring Security @WithMockUser does not work with cucumber TestsSpring Security @WithMockUser 不适用于黄瓜测试
【发布时间】:2016-08-03 17:02:26
【问题描述】:

我正在使用 cucumber 测试来测试我的 spring boot 应用程序并启用了 spring 安全性。除了我用 cucumber 测试运行我的测试套件时,我使用了一些使用 spring 安全性的测试。

    @WithMockUser(username = "BROWSER", roles =
   {"BROWSER","ADMIN"})

失败。如果我将它们作为简单的 junit 测试单独运行,但在使用黄瓜测试步骤运行时会失败,这些测试确实有效。 当我对黄瓜测试运行同样的问题时,这个问题看起来好像没有应用 spring 安全测试模拟行为。

我的黄瓜试运行类如下

@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/resources", monochrome = true, format =
{"pretty", "html:src/main/resources/static/cucumber"})
public class CucumberTests
{

}

我还注意到,当使用 <reuseForks>false</reuseForks> 通过 Maven 运行时,同样的工作原理。此外,如果未选中此选项,maven 触发的测试用例运行也会失败。

更新

AbstractIntegrationTest 类所有测试扩展

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Services.class,loader = SpringApplicationContextLoader.class)
//@IntegrationTest
@WebIntegrationTest(randomPort = true)
public abstract class AbstractIntegrationTest {

另一个不起作用的用例是使用这些注释是黄瓜特征条件,如下所示

@When("^I apply a GET on (.*)$")
    @WithMockUser(username = "BROWSER", roles = { "BROWSER", "ADMIN" })
    public void i_search_with_rsql(String query) throws Throwable {
    result = mvc.perform(get(uri, query));
    }

对此的任何帮助或解决方法。

【问题讨论】:

  • 要让 WithMockUser 工作,Spring Security 应用程序必须在与测试相同的进程/线程上运行。是这样吗?
  • @RobWinch 让我在没有 Cucumber 的情况下进行检查,当我在我的应用程序中运行所有测试时,这些运行良好。是 Cucumber 测试运行使我的测试单独运行。已使用 ABstractIntegrationTest 类更新了我的问题摘要,我的所有测试用例都继承自 。
  • @RobWinch 是否有替代 withMockUser 来模拟,因为如果您使用 then in 像这样的黄瓜测试,这些似乎也不起作用 @When("^I apply a GET on (.*)$" ) @WithMockUser(username = "BROWSER", roles = { "BROWSER", "ADMIN" }) public void i_search_with_rsql(String query) throws Throwable { result = mvc.perform(get(uri, query)); }
  • 如何设置 MockMvc 实例(即 mvc 变量)?
  • @RobWinch 目前我正在使用黄瓜 @Before 注释作为 @cucumber.api.java.Before public void setUp() { this.mvc = MockMvcBuilders.webAppContextSetup(context). build(); }

标签: java spring spring-security


【解决方案1】:

为了回应 Rob Winch 的回答,我的工作是使用他的方法减去该行 ".apply(springSecurity())"

【讨论】:

    【解决方案2】:

    WithMockUser 不适用于 Cucumber。改用黄瓜钩。

    WithMockUser 依赖于 Spring 的测试上下文支持中的 TestExecutionListener#beforeTestMethod,但在使用 Cucumber runner 运行时不会调用它们。这是因为 Cucumber 运行的场景由步骤组成,而不是标准的 JUnit 测试方法。

    选项 1 - 安全上下文挂钩。您可以使用挂钩设置安全上下文,例如:

    @ActiveProfiles("test")
    @SpringBootTest(classes = MyServer.class)
    @AutoConfigureMockMvc
    @AutoConfigureRestDocs
    @AutoConfigureCache
    public class MyServerContextHooks {
    
      @Before
      public void onBeforeScenario(final Scenario scenario) {
        // This method does nothing - context setup is done with annotations
      }
    }
    

    场景注释示例:

    @WithAdminUser
    Scenario: Run action as admin
        ...
    

    在场景中使用注释的示例钩子:

    public class TestUserHooks {
    
      @Before("@WithAdminUser")
      public void setupAdminUser() {
        SecurityContextHolder.getContext().setAuthentication(
                new UsernamePasswordAuthenticationToken(
                    "admin",
                    "N/A",
                    createAuthorityList("admin")));         
      }
    }
    

    选项 2 - 身份验证步骤。 另一种方法是使用特殊步骤为用户提供 mockMvc:

    Scenario: Run action as admin
        Given I am logged in as admin
        ...
    

    Stepdef 示例:

    public class SecurityTestSteps {
    
      @Autowired
      private MockMvcGlue mockMvc;
    
      @Autowired
      private OAuth2Mocks oauth2Mocks;
    
      @Autowired
      private TestUsers users;
    
      /**
       * Provides a one of predefined role-based authentications for the current request.
       */
      @Given("^I am logged in as (admin|editor|user)$")
      public void given_UserIsAuthenticatedWithRole(final String role) {
        switch (role) {
          case "admin":
            mockMvc.request().with(authentication(oauth2Mocks.auth(users.admin())));
            break;
          case "editor":
            mockMvc.request().with(authentication(oauth2Mocks.auth(users.edtior())));
            break;
          default:
            throw new CucumberException("Unsupported role <" + role + ">");
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

      根据您的 cmets,您需要确保应用 Spring Security。您可以在参考文档的Setting Up MockMvc and Spring Security section 中找到一个示例:

      import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
      
      // ...
      
      @Before
      public void setup() {
          mvc = MockMvcBuilders
                  .webAppContextSetup(context)
                  .apply(springSecurity()) // ADD THIS!
                  .build();
      }
      

      【讨论】:

      • 我猜以上内容适用于模拟 springsecuritychain 但现在我必须将模拟角色作为mvc.perform(get(uri, query).with(getAdminRole())); 放入获取请求中,尽管注释@WithMockUser 仍然不起作用,但无论如何我有得到了解决方法并且测试通过了:) 谢谢
      猜你喜欢
      • 2015-07-14
      • 2021-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多