最近我使用以下类将 Spring Security 添加到我的Spring Boot项目中:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig {
}
因此,默认情况下,我的所有URL现在都受到身份验证和自生密码的保护。
问题是我用于对控制器进行单元测试的@WebMvcTest类中的所有测试:
@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
public class SomeControllerTest {...}
由于缺乏授权,现在无处不在。
问题:我可以告诉@Test方法忽略授权,以便它们像以前一样继续成功吗?
如何防止在特定的 @WebMvcTest 单元测试类中挑选 @EnableWebSecurity 配置类?
我希望现有的测试能够在以后单独测试身份验证功能。
到目前为止,我尝试在测试类中使用嵌套的配置类来排除安全配置:
@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
public class SomeControllerTest {
@Configuration
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class})
static class ContextConfiguration { }
....}
但似乎没有用。
注意:我使用的是Spring Boot 1.5.8
答案 0 :(得分:28)
对我来说,在Spring Boot 2.2.4(JUnit5)中,以下内容似乎已经奏效并绕过了安全过滤器。
@ExtendWith(SpringExtension.class)
@WebMvcTest(SomeController.class)
@AutoConfigureMockMvc(addFilters = false)
public class SomeControllerTest {
...
注意:这只是禁用了SpringSecurity配置中的所有过滤器。它不会完全禁用安全性。换句话说,它仍然可以引导安全性,而无需加载任何过滤器。
答案 1 :(得分:17)
您可以在@WebMvcTest annoation中设置 secure = false 。 它将跳过测试中的弹簧安全性MockMvc自动配置
import numpy as np
a = np.array([[1, 2, 4, 0, -2, 6],
[3, 5, 4, 9, 10, -3],
[4, 6, 0, -5, 11, 2],
[0, -3, -4, 0, 12, 8]])
a[:, a.shape[1]//2:] = 0
print(a)
答案 2 :(得分:7)
在Spring Boot 2.2.6中,@ WebMvcTest带有@AutoConfigureWebMvc的元注释,该属性自动配置org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,如您在spring-boot-test-的spring.factory中所见。 autoconfigure.jar
因此您只需要在测试中排除SecurityAutoConfiguration即可禁用Spring Security:
@WebMvcTest(excludeAutoConfiguration = SecurityAutoConfiguration.class)
答案 3 :(得分:5)
在 Spring Boot 2.4 中,两个 secure
标志都被删除了,这里的答案都没有实际工作。
我最终自己排除了所有安全性,并将其封装在自定义注释中。
import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@WebMvcTest(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = WebSecurityConfigurer.class)},
excludeAutoConfiguration = {SecurityAutoConfiguration.class,
SecurityFilterAutoConfiguration.class,
OAuth2ClientAutoConfiguration.class,
OAuth2ResourceServerAutoConfiguration.class})
public @interface UnsecuredWebMvcTest {
@AliasFor(annotation = WebMvcTest.class, attribute = "controllers")
Class<?>[] value() default {};
@AliasFor(annotation = WebMvcTest.class, attribute = "controllers")
Class<?>[] controllers() default {};
}
答案 4 :(得分:2)
在Spring Security 4+中,我发现tap
注释非常方便。它提供了一个模拟用户和密码来测试以@PreAuthorize或@PostAuthorize注释的spring安全方法。您需要做的就是用@WithMockUser
注释测试方法。用户的默认角色是@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
}
答案 5 :(得分:2)
这对我有用,使用Spring Boot 2.3.1。
@ExtendWith(SpringExtension.class)
@WebMvcTest(SomeController.class)
@AutoConfigureMockMvc(addFilters = false)
public class SomeControllerTest {
}
答案 6 :(得分:1)
我知道这是Spring Boot 1.5的一个特定问题,但似乎有点老了。为了成功运行OAuth2安全控制器单元测试,我应用了以下步骤,请注意,我使用了Spring Boot 2.2.6,Gradle 5.x和JUnit5。此机制应以基于{{ 1}}或@AutoConfigureMockMvc(secure = false)
这是针对使用Microsoft的Azure Active Directory保护(OAuth2)的REST API项目,但本质上,此测试策略应适用于任何OIDC,OAuth2配置。
技巧是拥有一个控制器测试文件并使用@WebMvcTest批注对其进行批注,但是,需要以下参数:
@WebMvcTest(controllers = SomeController.class, secure = false)
这里是使测试成功运行的配置。
build.gradle
@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
)
}
)
GreetController.java
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()
}
WebSecurityConfig.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";
}
}
application.properties
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);
}
}
GreetControllerTest.java
azure.activedirectory.client-id=xxxxx-AD-client-id-goes-here
azure.activedirectory.session-stateless=true
我了解到要使用完全不同的方法来进行基于JUnit 4的相似测试,可以将以下测试用作参考(但我没有尝试过):https://github.com/spring-projects/spring-security/blob/master/samples/boot/oauth2resourceserver/src/test/java/sample/OAuth2ResourceServerControllerTests.java