java 在 Spring Boot 中为 @WebMvcTest 禁用 Spring Security 配置类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47593537/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 09:41:41  来源:igfitidea点击:

Disable Spring Security config class for @WebMvcTest in Spring Boot

javaspringspring-mvcspring-bootspring-security

提问by Johan

Recently I have added Spring Securityto my Spring Boot project using the following class:

最近,我使用以下类将Spring Security添加到我的 Spring Boot 项目中:

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

as result, by default all my URLs are now protected with authentication and a self-generated password.

因此,默认情况下,我的所有 URL 现在都受到身份验证和自行生成的密码的保护。

The problem is that all tests in a @WebMvcTest class that I used for unit-testing a controller:

问题是我用于对控制器进行单元测试的 @WebMvcTest 类中的所有测试:

@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
public class SomeControllerTest {...}

are now failing everywhere because of lack of authorization.

由于缺乏授权,现在到处都失败了。

Question: can I tell @Test methods to ignore authorization so they keep succeeding as before?

问题:我可以告诉@Test 方法忽略授权,以便它们像以前一样继续成功吗?

How can I prevent the @EnableWebSecurityconfig class from being picked on a specific @WebMvcTestunit testing class?

如何防止在 特定的@WebMvcTest单元测试类上选择@EnableWebSecurity配置类?

I would like the tests already in place to be able to still go through and to test the authentication features separately later on.

我希望已经到位的测试仍然能够通过并在以后单独测试身份验证功能。

So far I have tried to use a nested config class in the testing class in order to exclude security configs:

到目前为止,我已经尝试在测试类中使用嵌套的配置类来排除安全配置:

@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
public class SomeControllerTest {

    @Configuration
    @EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class})
    static class ContextConfiguration { }

 ....}

but it seems not to work.

但它似乎不起作用。

NOTE: I am using Spring Boot 1.5.8

注意:我使用的是 Spring Boot 1.5.8

回答by Mzzl

You can set secure=falsein the @WebMvcTest annoation. It will skip the spring security MockMvc auto configuration in your Test

您可以在 @WebMvcTest 注释中设置secure=false。它将跳过测试中的 spring security MockMvc 自动配置

@WebMvcTest(controllers = SomeController.class, secure = false)
public class SomeControllerTest {

回答by theo

For me in Spring Boot 2.2.4 (JUnit5) the below seems to have worked and bypass the security filter.

对我来说,在 Spring Boot 2.2.4 (JUnit5) 中,以下内容似乎有效并绕过了安全过滤器。

@ExtendWith(SpringExtension.class)
@WebMvcTest(SomeController.class)
@AutoConfigureMockMvc(addFilters = false)
public class SomeControllerTest {
...

Note: this simply disables any filters in the SpringSecurity configuration. It won't disable the security completely. In other words it will still bootstrap security without loading any filters.

注意:这只是禁用 SpringSecurity 配置中的任何过滤器。它不会完全禁用安全性。换句话说,它仍然会在不加载任何过滤器的情况下引导安全性。

回答by alltej

With Spring Security 4+, I find @WithMockUserannotation to be very handy. It provides a mock user and password to test spring security methods annotated with @PreAuthorize or @PostAuthorize. All you need to do is annotate the test method with @WithMockUser. The default role for the user is USER. You can override the default username and role too.

使用 Spring Security 4+,我发现@WithMockUser注释非常方便。它提供了一个模拟用户和密码来测试用@PreAuthorize 或@PostAuthorize 注释的spring 安全方法。您需要做的就是使用@WithMockUser. 用户的默认角色是USER。您也可以覆盖默认用户名和角色。

//default
@Test
@WithMockUser
public void getProfile() {
   //your test here
} 

//with username and roles
@Test
@WithMockUser(username = "john", roles={"ADMIN"})
public void getProfile() {
   //your test here
} 

NOTE: This annotation can be used for classes.

注意:此注释可用于类。

@WithMockUser(username = "john", roles={"ADMIN"})
public class UsersAdminSecurityTest {
} 

回答by Fabien

In Spring Boot 2.2.6, @WebMvcTest is meta annotated with @AutoConfigureWebMvc which auto-configure org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration as you can see in spring.factories of spring-boot-test-autoconfigure.jar

在 Spring Boot 2.2.6 中,@WebMvcTest 使用 @AutoConfigureWebMvc 进行元注释,它自动配置 org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,如您在 spring-boot-test-autoconfigure.jar 的 spring.factories 中所见

So you just have to exclude SecurityAutoConfiguration in your test to disable Spring Security :

因此,您只需在测试中排除 SecurityAutoConfiguration 即可禁用 Spring Security:

@WebMvcTest(excludeAutoConfiguration = SecurityAutoConfiguration.class) 

回答by darkstar_mx

I understand this is a specific question for Spring Boot 1.5 but seems a bit old. In order to have a successful OAuth2 secured controller unit test running I applied the following steps, kindly notice I used Spring Boot 2.2.6, Gradle 5.x, and JUnit 5. This mechanism should work the same way deprecated ones based on @AutoConfigureMockMvc(secure = false)or @WebMvcTest(controllers = SomeController.class, secure = false)

我知道这是 Spring Boot 1.5 的一个特定问题,但似乎有点旧。为了成功运行 OAuth2 安全控制器单元测试,我应用了以下步骤,请注意我使用了 Spring Boot 2.2.6、Gradle 5.x 和 JUnit 5。这种机制应该与基于@AutoConfigureMockMvc(secure = false)@WebMvcTest(controllers = SomeController.class, secure = false)

This is for a REST API project that is secured (OAuth2) using Microsoft's Azure Active Directory, but essentially this testing strategy should work for any OIDC, OAuth2 configuration.

这是针对使用 Microsoft 的 Azure Active Directory 进行保护 (OAuth2) 的 REST API 项目,但本质上该测试策略应该适用于任何 OIDC、OAuth2 配置。

The trick is to have a Controller test file and annotate it with @WebMvcTest annotation, however, the following parameters are required:

诀窍是有一个控制器测试文件并使用@WebMvcTest 注释对其进行注释,但是,需要以下参数:

@WebMvcTest(
        value = YourController.class

        // this disables loading up the WebSecurityConfig.java file, otherwise it fails on start up
        , useDefaultFilters = false

        // this one indicates the specific filter to be used, in this case
        // related to the GreetController we want to test
        , includeFilters = {
        @ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                value = YourController.class
        )
        }
)

Here the configurations that make the test run successfully.

这里是使测试成功运行的配置。

build.gradle

构建.gradle

plugins {
    id 'org.springframework.boot' version '2.2.6.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
}

group = 'com.grailscoder'
version = '0.0.1-SNAPSHOT'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

ext {
    set('azureVersion', "2.2.4")
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.microsoft.azure:azure-active-directory-spring-boot-starter'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
    testImplementation 'org.junit.jupiter:junit-jupiter-params:5.5.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
}

dependencyManagement {
    imports {
        mavenBom "com.microsoft.azure:azure-spring-boot-bom:${azureVersion}"
    }
}

test {
    useJUnitPlatform()
}

GreetController.java

问候控制器.java

package com.grailscoder.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
public class GreetController {

    @GetMapping("/greets")
    @PreAuthorize("hasRole('ROLE_USER')")   // This is validating against Active Directory's User role granted to the
                                            // current user.
    @ResponseStatus(HttpStatus.OK)
    public String getGreetMessage() {
        return "Greets from secret controller";
    }
}

WebSecurityConfig.java

网络安全配置文件

package com.grailscoder.config;

import com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@RequiredArgsConstructor
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final AADAppRoleStatelessAuthenticationFilter aadAuthFilter;

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

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);

        http.authorizeRequests()
                .antMatchers("/", "/index.html", "/public").permitAll()
                .anyRequest().authenticated();
        http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);

    }
}

application.properties

应用程序属性

azure.activedirectory.client-id=xxxxx-AD-client-id-goes-here
azure.activedirectory.session-stateless=true

GreetControllerTest.java

问候控制器测试.java

package com.grailscoder.controller;

import com.fasterxml.Hymanson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(
        value = GreetController.class

        // this disables loading up the WebSecurityConfig.java file, otherwise it fails on start up
        , useDefaultFilters = false

        // this one indicates the specific filter to be used, in this case
        // related to the GreetController we want to test
        , includeFilters = {
        @ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                value = GreetController.class
        )
        }
)
class GreetControllerTest {

    @Autowired
    MockMvc mockMvc;

    @Autowired
    ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        // add setup stuff here
    }

    @Test
    @WithMockUser
    void testGreet() throws Exception {

        ResultActions result = mockMvc.perform(get("/greets"))
                .andExpect(status().isOk());
        System.out.println(result.andReturn().getResponse().getContentAsString());

    }


}

I understand in order to have a similar test JUnit 4 based with a completely different approach, the following test could be used as a reference (but I haven't tried): https://github.com/spring-projects/spring-security/blob/master/samples/boot/oauth2resourceserver/src/test/java/sample/OAuth2ResourceServerControllerTests.java

我了解为了使用完全不同的方法进行类似的测试 JUnit 4,可以使用以下测试作为参考(但我没有尝试过):https: //github.com/spring-projects/spring- security/blob/master/samples/boot/oauth2resourceserver/src/test/java/sample/OAuth2ResourceServerControllerTests.java