java - 在 oAuth2 资源服务器应用程序中使用@WithMockUser(与@SpringBootTest)

标签 java spring-mvc spring-boot spring-security spring-test-mvc

环境: 我有一个基于 spring boot 的微服务架构应用程序,由多个基础设施服务和资源服务(包含业务逻辑)组成。授权和身份验证由管理用户实体并为客户端创建 JWT token 的 oAuth2 服务处理。

为了完整地测试单个微服务应用程序,我尝试使用 testNGspring.boot.testorg.springframework.security.test 构建测试 ...

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, properties = {"spring.cloud.discovery.enabled=false", "spring.cloud.config.enabled=false", "spring.profiles.active=test"})
@AutoConfigureMockMvc
@Test
public class ArtistControllerTest extends AbstractTestNGSpringContextTests {

  @Autowired
  private MockMvc mvc;

  @BeforeClass
  @Transactional
  public void setUp() {
    // nothing to do
  }

  @AfterClass
  @Transactional
  public void tearDown() {
    // nothing to do here
  }

  @Test
  @WithMockUser(authorities = {"READ", "WRITE"})
  public void getAllTest() throws Exception {

    // EXPECT HTTP STATUS 200
    // BUT GET 401
    this.mvc.perform(get("/")
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
  }
}

安全(资源服务器)配置如下

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

  // get the configured token store
  @Autowired
  TokenStore tokenStore;

  // get the configured token converter
  @Autowired
  JwtAccessTokenConverter tokenConverter;

  /**
   * !!! configuration of springs http security !!!
   */
  @Override
  public void configure(HttpSecurity http) throws Exception {
      http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/**").authenticated();
  }

  /**
   * configuration of springs resource server security
   */
  @Override
  public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
    // set the configured tokenStore to this resourceServer
    resources.resourceId("artist").tokenStore(tokenStore);
  }

}

以及以下在 Controller 类中注释的基于方法的安全检查

@PreAuthorize("hasAuthority('READ')")
@RequestMapping(value = "/", method = RequestMethod.GET)
public List<Foo> getAll(Principal user) {
    List<Foo> foos = fooRepository.findAll();
    return foos;
}

我认为这行得通,但是在运行测试时我只得到一个断言错误

java.lang.AssertionError: Status 
Expected :200
Actual   :401


问题: 有什么完全明显的我做错了吗?还是 @WithMockUser 不会在 oAuth2 环境中与 @SpringBootTest 和 @AutoConfigureMockMvc 一起工作?如果是这种情况...作为此类(集成)测试的一部分,测试基于路由和方法的安全配置的最佳方法是什么?


附录: 我也尝试了不同的方法,如下所示......但它导致了相同的结果:(

this.mvc.perform(get("/")
        .with(user("admin").roles("READ","WRITE").authorities(() -> "READ", () -> "WRITE"))
        .accept(MediaType.APPLICATION_JSON))

参见:
spring security testing
spring boot 1.4 testing

最佳答案

@WithMockUserSecurityContext 中创建身份验证。 这同样适用于 with(user("username"))

默认情况下,OAuth2AuthenticationProcessingFilter 不使用 SecurityContext,但始终从 token (“无状态”)构建身份验证。

通过将资源服务器安全配置中的无状态标志设置为 false,您可以轻松更改此行为:

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration implements ResourceServerConfigurer {

    @Override
    public void configure(ResourceServerSecurityConfigurer security) throws Exception {
        security.stateless(false);
    }

    @Override
    public void configure(HttpSecurity http) {}

}

另一种选择是扩展 ResourceServerConfigurerAdapter,但问题是它带有强制对所有请求进行身份验证的配置。除了无状态之外,实现该接口(interface)会使您的主要安全配置保持不变。

当然,仅在您的测试上下文中将标志设置为 false

关于java - 在 oAuth2 资源服务器应用程序中使用@WithMockUser(与@SpringBootTest),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41824885/

相关文章:

java - 外部化 namespace JAXB 生成的 package-info.java

java - 无法使用 GSON 比较两个 json 文件

java - spring mvc 为所有 Controller 提供一个初始化绑定(bind)器

java - 我如何从 keystore 中获取 secret ?

java - 如何暂停 Runnable() 对象以进行测试

javascript - 安卓应用 : Pass Javascript Var to Native Java variable

spring - DispatcherServlet : No mapping found for HTTP request with URI

java - 如何在不使用注释的情况下创建 Spring Controller ?

Spring Boot 不读取 data.sql 但它读取 import.sql

java - 如何在过滤器中匹配此 url 模式