spring 运行配置文件时禁用@PreAuthorize注解

2ledvvac  于 2023-08-02  发布在  Spring
关注(0)|答案(2)|浏览(226)

我用cucumber测试框架为Sping Boot Application编写了API功能测试用例。在具有测试用例专用配置的配置文件中启动spring Boot 应用程序后,使用以下命令执行测试:

mvn spring-boot:start -Dspring-boot.run.profiles=test -Dspring-boot.run.arguments="--spring.config.name=application-test --spring.config.location=./src/test/resources/application-test.yaml" test spring-boot:stop -DskipTests=false

字符串
一旦spring应用程序启动,并且在测试中验证了响应,API调用就从测试用例中进行。
我已经使用下面给出的自定义WebSecurityConfigurerAdapter在测试用例中禁用了安全性:

@TestConfiguration
@Order(1)
@Profile("test")
public class TestSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .anyRequest()
                .permitAll();
    }

}


安全已禁用。但是有一些控制器的角色是用@PreAuthorize注解检查的。使用@PreAuthorize注解对控制器进行的调用失败,并出现以下错误:

{
    "timestamp": 1689838624242,
    "errorType": "UNKNOWN",
    "errors": [
        "Access is denied"
    ]
}


尝试了几个选项来禁用特定配置文件的预授权字段,但它们都不起作用。感谢任何关于如何禁用@PreAuthorize检查选定的配置文件或在Cucumber的测试用例中的想法。
已尝试的选项:
1.在测试中设置@EnableGlobalMethodSecurity(prePostEnabled = true)。没有用
1.引用此SO answer。我的 Boot 应用程序是用Oauth2保护的,我在测试中禁用了它。所以发送基本的认证凭证将不起作用。

des4xlb0

des4xlb01#

@Given步骤中设置测试安全上下文,而不是禁用安全性。
示例取自this README,我写的(当时Keycloak for Spring的适配器没有被弃用):
小 cucumber 功能:

Feature: Testing a secured REST API
  Users should be able to GET greetings only if authenticated

  Scenario: Authorized users should be greeted
    Given the following user roles:
      | ROLE_user   |
      | ROLE_TESTER |
    When a get request is sent to greeting endpoint
    Then a greeting is returned

  Scenario: Unauthorized users should not be able to access greetings
    Given user is not authenticated
    When a get request is sent to greeting endpoint
    Then 401 is returned

字符串
下面使用了一些来自com.c4-soft.springaddons:spring-addons-oauth2-test的代码,这是我在maven-central上发布的一个库,以简化定义OpenID声明。如果您对索赔详细信息不感兴趣,则可以跳过此依赖关系(如果授权机构和用户名足够):

public class JwtTestingBuilder {
    protected final OpenidClaimSetBuilder claimsBuilder;
    private final Set<String> authorities;
    private String bearerString = "machin.truc.chose";
    private Map<String, Object> headers = new HashMap<>(Map.of("machin", "truc"));

    public JwtTestingBuilder() {
        this.claimsBuilder = new OpenidClaimSetBuilder().subject(Defaults.SUBJECT).name(Defaults.AUTH_NAME);
        this.authorities = new HashSet<>(Defaults.AUTHORITIES);
    }

    public JwtAuthenticationToken build() {
        final var claims = claimsBuilder.build();
        final var iat = Instant.now();
        final var exp = iat.plusMillis(60000);
        final var jwt = new Jwt(bearerString, iat, exp, headers, claims);
        return new JwtAuthenticationToken(jwt, authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet()), claims.getName());
    }

    public JwtTestingBuilder authorities(String... authorities) {
        return authorities(Stream.of(authorities));
    }

    public JwtTestingBuilder authorities(Stream<String> authorities) {
        this.authorities.clear();
        this.authorities.addAll(authorities.toList());
        return this;
    }

    public JwtTestingBuilder claims(Consumer<OpenidClaimSetBuilder> tokenBuilderConsumer) {
        tokenBuilderConsumer.accept(claimsBuilder);
        return this;
    }

    public JwtTestingBuilder bearerString(String bearerString) {
        this.bearerString = bearerString;
        return this;
    }
}


步骤:

public class GreetingControllerSuite {

    @Autowired
    MockMvc mockMvc;

    MvcResult result;

    @Given("user is not authenticated")
    public void unauthenticatedUser() {
        TestSecurityContextHolder.clearContext();
    }

    @Given("the following user roles:")
    public void authenticateAsUser(List<String> rolesTable) {
        TestSecurityContextHolder.clearContext();
        final Stream<String> roles = rolesTable.stream().map(String::trim);
        TestSecurityContextHolder.setAuthentication(new JwtTestingBuilder().authorities(roles).build());
    }

    @When("a get request is sent to greeting endpoint")
    public void getGreet() throws Exception {
        result = mockMvc.perform(get("/greet")).andReturn();
    }

    @Then("401 is returned")
    public void unauthorizedStatus() throws Exception {
        assertEquals(401, result.getResponse().getStatus());
    }

    @Then("a greeting is returned")
    public void greetingIsReturned() throws Exception {
        assertEquals(200, result.getResponse().getStatus());
        final var body = result.getResponse().getContentAsString();
        assertThat(body.contains("Hello user! You are granted with "));
        assertThat(body.contains("ROLE_user"));
        assertThat(body.contains("ROLE_TESTER"));
    }
}


cucumber JUnit 4适配器:

import org.junit.runner.RunWith;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)
@CucumberOptions(features = "classpath:cucumber-features", plugin = {
        "pretty",
        "html:target/cucumber" }, extraGlue = "com.c4_soft.springaddons.samples.webmvc.cucumber.extraglue")
public class CucumberIntegrationTest {
}


Spring“外胶”:

package com.c4_soft.springaddons.samples.webmvc.cucumber.extraglue;

...

@CucumberContextConfiguration
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@ContextConfiguration(classes = { SpringBootSampleApp.class })
@AutoConfigureMockMvc
public static class CucumberSpringConfiguration {
}

qxsslcnc

qxsslcnc2#

解决方案之一是使用Mock impl,即类级别或方法级别的以下注解:
第一个月
For more details read it

相关问题