我正在编写 jUnit 测试来测试我的资源服务器的端点。
现在,这些端点通过 @PreAuthorized (和类似的)注释进行保护,如下所示:
@PreAuthorize("hasAuthority('SCOPE_data.write')")
@PostMapping("/save")
public ResponseEntity<Book> saveBook(
@io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "Save book",
required = true,
content = @Content(schema = @Schema(implementation = Book.class)))
@Valid @org.springframework.web.bind.annotation.RequestBody Book book){
try {
Book _book = bookRepo.save(new Book(book.getID(), vehicle.getTitle(), vehicle.getAuthor()));
return new ResponseEntity<>(_book, HttpStatus.CREATED);
}catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
我的单元测试将是这样的:
@Test
public void testSaveBook() throws Exception {
this.mockMvc.perform(
post("/book/save")
.contentType(MediaType.APPLICATION_JSON)
.content(bookToSave))
.with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_data.write")))
.andDo(print())
.andExpect(status().isOk));
}
这是我的安全配置:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(exchanges -> exchanges
.antMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
.anyRequest().authenticated())
.csrf().disable()
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
jwt()
测试DSL(域特定语言)中的MockMvc
方法用于在测试中模拟JWT身份验证。让我们一一回答您的问题:
为什么我的端点可以使用此令牌访问?为什么我的资源服务器接受这个令牌?
当您在
jwt().authorities(new SimpleGrantedAuthority("SCOPE_data.write"))
测试上下文中使用 MockMvc
时,您实际上是在创建一个模拟(模拟)JWT 身份验证以进行测试。它绕过正常的 JWT 处理和验证(签名、过期、颁发者等),并直接模拟使用具有给定权限的 JWT 进行身份验证的用户。这只是为了测试;在现实场景中,实际的 JWT 将根据您的资源服务器的配置进行处理和验证。
有了这个令牌,任何用户都可以访问我的端点,从而访问数据库内的数据吗?
不可以,真实用户无法在生产环境中使用“alg: none”令牌来访问您的端点。这是一种仅在
MockMvc
框架范围内有效的测试机制。在生产中,令牌将被拒绝,因为它未签名。值得注意的是,在真正的 JWT 处理中允许“none”作为算法存在安全风险,但这并不是这里发生的情况。这仅适用于测试场景。
该代币的使用是否存在安全问题?
只要这个模拟的 JWT 身份验证严格在测试环境范围内使用,而不是在生产中使用,就不应该有安全问题。这是 Spring Security 提供的用于测试目的的实用程序。你本质上是在说,“让我们假设我们与这些机构有一个有效的 JWT,然后看看系统的行为如何。”
但是,一些最佳实践和附加说明:
最后,当您的测试检查
status().isOk
时,实际端点会在保存书籍时返回 HttpStatus.CREATED
(201)。您可能需要更新测试以检查 status().isCreated()
而不是 isOk()
,以更准确地反映预期行为。