java Spring boot,禁用测试的安全性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32956829/
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
Spring boot, disable security for tests
提问by Hollow.Quincy
I use spring boot version "1.3.0.M5" (I also tried version "1.2.5.RELEASE"). I added spring security:
我使用 Spring Boot 版本“1.3.0.M5”(我也尝试过版本“1.2.5.RELEASE”)。我添加了弹簧安全性:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
and code:
和代码:
@SpringBootApplication
public class SpringBootMainApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMainApplication.class, args);
}
}
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/sampleentity").authenticated()
.and().authorizeRequests()
.and().formLogin().permitAll()
.and().logout().permitAll().logoutUrl("/logout")
.logoutSuccessUrl("/");
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
@RestController
@RequestMapping("/api/sampleentity")
public class SampleEntityController {
@RequestMapping(method= RequestMethod.GET)
public Iterable<SampleEntity> getAll() {
return ImmutableSet.of();
}
@RequestMapping(method=RequestMethod.POST)
@ResponseStatus(value= HttpStatus.CREATED)
public SampleEntity create(@RequestBody SampleEntity sampleEntity) {
return sampleEntity;
}
}
and test that is failing when /api/sampleentity is access: org.springframework.web.client.HttpClientErrorException: 403 Forbidden (...)
并在访问 /api/sampleentity 时测试失败:org.springframework.web.client.HttpClientErrorException: 403 Forbidden (...)
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootMainApplication.class)
@WebAppConfiguration
@IntegrationTest({"server.port=0"})
public class SampleEntityTest {
@Value("${local.server.port}")
private int port;
private String url;
private RestTemplate restTemplate;
@Autowired
private ApplicationContext context;
@BeforeClass
public static void authenticate(){
//ONE TRY
// Authentication authentication =
// new UsernamePasswordAuthenticationToken("user", "password",
// AuthorityUtils.createAuthorityList("USER")); //tried "ROLE_USER"
// SecurityContextHolder.getContext().setAuthentication(authentication);
}
@Before
public void setUp() {
url = String.format("http://localhost:%s/api/sampleentity", port);
restTemplate = new RestTemplate();
//ANOTHER TRY
// AuthenticationManager authenticationManager = context.getBean(AuthenticationManager.class);
// Authentication authentication = authenticationManager
// .authenticate(new UsernamePasswordAuthenticationToken("user", "password", AuthorityUtils.createAuthorityList("USER"))); //tried "ROLE_USER"
// SecurityContextHolder.getContext().setAuthentication(authentication);
}
//THIS METHOD SHOULD WORK !
@Test
//ANOTHER TRY
//@WithMockUser(username="user",password = "password", roles={"USER"})//tried "ROLE_USER"
public void testEntity_create() throws Exception {
SampleEntity sampleEntity = create("name", 1);
ResponseEntity<SampleEntity> response = restTemplate.postForEntity(url, sampleEntity, SampleEntity.class);
assertEquals(HttpStatus.CREATED, response.getStatusCode());
}
private SampleEntity create(String name, int id) {
SampleEntity entity = new SampleEntity();
entity.setName(name);
entity.setId(id);
return entity;
}
}
When I run application from main() and access url: http://localhost:8080/api/sampleentityI am redirected to login page.
当我从 main() 运行应用程序并访问 url: http://localhost:8080/api/sampleentity我被重定向到登录页面。
How can I run my test and disable security or just log in user ?
如何运行测试并禁用安全性或仅登录用户?
--my solution: exclude security from the test using profiles:
--我的解决方案:使用配置文件从测试中排除安全性:
@SpringBootApplication
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class})
public class SpringBootMainApplication {body the same}
@EnableWebSecurity
@Import(SecurityAutoConfiguration.class)
@Profile("!test")
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {body the same}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootMainApplication.class)
@WebAppConfiguration
@IntegrationTest({"server.port=0"})
@ActiveProfiles("test")
public class SampleEntityTest {body the same}
回答by BeWu
You have to do some changes to your config and test to solve your problem(s).
您必须对配置进行一些更改并进行测试以解决您的问题。
First I'll explain why your solution isn't working:
首先,我将解释为什么您的解决方案不起作用:
- The Spring
RestTemplateclass is a possible way to access your REST service but lacks some header informations the way it is constructed (Which doesn't mean it's impossible with theRestTemplate). Thats why the authentication didn't work. - My first solution attempt isn't working because of the usage of the
RestTemplateclass, as theRestTemplaterequest is likely to create a new session. It sets an entirely different environment. My code works if you want to test Methods secured with the@PreAuthorizeannotation but only if you want to execute such a method directly in your test and you need a valid authentication. - You can't automatically authorize any user as of your current spring security configuration.
- Spring
RestTemplate类是一种访问 REST 服务的可能方式,但它的构造方式缺少一些标头信息(这并不意味着它不可能使用RestTemplate)。这就是身份验证不起作用的原因。 - 由于
RestTemplate该类的使用,我的第一个解决方案尝试不起作用,因为该RestTemplate请求可能会创建一个新会话。它设置了一个完全不同的环境。如果您想测试使用@PreAuthorize注释保护的方法,但仅当您想直接在测试中执行此类方法并且需要有效的身份验证时,我的代码才有效。 - 根据当前的 spring 安全配置,您无法自动授权任何用户。
Second, here are the necessary changes to your code:
其次,以下是对代码的必要更改:
First the configuration class
首先是配置类
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER" );
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().csrf().disable()
.authorizeRequests().antMatchers("/api/sampleentity").authenticated()
.and().authorizeRequests().antMatchers("/users").hasRole("ADMIN")
.and().formLogin().permitAll()
.and().logout().permitAll().logoutUrl("/logout")
.logoutSuccessUrl("/");
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
I had to add httpBasic Authentication support (to enable authentication via http header attribute) and I disabled csrf tokens (the latter just for convenience, you should reenable them according to criticality of your application).
我必须添加 httpBasic Authentication 支持(以通过 http 标头属性启用身份验证)并禁用了 csrf 令牌(后者只是为了方便起见,您应该根据应用程序的重要性重新启用它们)。
And second the Testclass:
其次是测试类:
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import javax.servlet.Filter;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingHymanson2HttpMessageConverter;
import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootMainApplication.class)
@WebAppConfiguration
@IntegrationTest({ "server.port=0" })
public class SampleEntityTest {
private String url;
private MockMvc mockMvc;
private HttpMessageConverter mappingHymanson2HttpMessageConverter;
private MediaType contentType = new MediaType(
MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
@Autowired
private WebApplicationContext webApplicationContext;
@Autowired
private Filter springSecurityFilterChain;
@Autowired
void setConverters(HttpMessageConverter<?>[] converters) {
for (HttpMessageConverter hmc : Arrays.asList(converters)) {
if (hmc instanceof MappingHymanson2HttpMessageConverter) {
this.mappingHymanson2HttpMessageConverter = hmc;
}
}
Assert.assertNotNull("the JSON message converter must not be null",
this.mappingHymanson2HttpMessageConverter);
}
@Before
public void setUp() {
url = "/api/sampleentity";
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilters(springSecurityFilterChain).build();
}
@Test
public void testEntityGet() throws Exception {
mockMvc.perform(
get(url)
.with(httpBasic("user", "password")))
.andExpect(status().isOk());
}
@Test
public void testEntityPost() throws Exception {
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setName("name");
sampleEntity.setId(1);
String json = json(sampleEntity);
mockMvc.perform(
post(url)
.contentType(contentType)
.content(json)
.with(httpBasic("user", "password")))
.andExpect(status().isCreated());
}
protected String json(Object o) throws IOException {
MockHttpOutputMessage mockHttpOutputMessage = new MockHttpOutputMessage();
this.mappingHymanson2HttpMessageConverter.write(o,
MediaType.APPLICATION_JSON, mockHttpOutputMessage);
return mockHttpOutputMessage.getBodyAsString();
}
}
}
I have used the spring/ spring security test approach here.
我在这里使用了 spring/spring 安全测试方法。
Versions used:
使用的版本:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.0.2.RELEASE</version>
<scope>test</scope>
</dependency>
If you want to test your rest api i can recommend you the Postman plugin for Chrome. As that can help you identify the problem much faster.
如果你想测试你的 rest api,我可以向你推荐 Chrome 的 Postman 插件。因为这可以帮助您更快地识别问题。
I hope this helps you to finally solve your problem.
我希望这可以帮助您最终解决您的问题。
回答by Kunal Vohra
If you want to see what's being auto-configured, launch your web app and access the autoconfig endpoint (e.g., http://localhost:8080/autoconfig). Then search for 'Security' to see which 'AutoConfiguration' classes are being detected.
如果您想查看自动配置的内容,请启动您的 Web 应用程序并访问自动配置端点(例如,http://localhost:8080/autoconfig)。然后搜索“ Security”以查看AutoConfiguration正在检测哪些“ ”类。
You can then disable auto-configuration of security by excluding those classes like this:
然后,您可以通过排除这些类来禁用安全性的自动配置,如下所示:
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, ManagementSecurityAutoConfiguration.class })
Of course, you won't want to exclude them for production deployments. Thus you'll need to have a separate @Configurationclass for production and tests.
当然,您不会希望将它们排除在生产部署中。因此,您需要有一个单独的@Configuration类用于生产和测试。
Orif you want a detailed answer go for below-mentioned steps
或者,如果您想要详细的答案,请执行以下步骤
Add annotation @Profile(value = {"development", "production"})to my implementation of WebSecurityConfigurerAdapter
@Profile(value = {"development", "production"})在我的实现中添加注释WebSecurityConfigurerAdapter
@Configuration
@EnableWebSecurity
@Profile(value = {"development", "production"})
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
Now, in test/resources, create application-test.yml to define properties for test profile and add this -
现在,在 test/resources 中,创建 application-test.yml 来定义测试配置文件的属性并添加这个 -
# Security enable/disable
security:
basic:
enabled: false
Now, to your test cases, add this annotation to apply the active profile @ActiveProfiles(value = "test"). This is how my class looked -
现在,在您的测试用例中,添加此注释以应用活动配置文件 @ActiveProfiles(value = "test")。这是我班级的样子——
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@ActiveProfiles(value = "test")
@IntegrationTest({"server.port=0"})
public class SampleControllerIntegrationTest {
Doing this will disabled security for tests. Best of luck!!!
这样做将禁用测试的安全性。祝你好运!!!

