You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot:如何测试带自定义PreAuthorize表达式与认证的REST API

测试带有自定义权限校验的Spring Boot REST API方案

针对你这个结合了Spring Security自定义权限校验的Spring Boot REST API,我整理了一套实用的测试方案,覆盖核心场景,同时保持测试的独立性:

核心思路

咱们需要:

  • 聚焦测试Controller层的权限逻辑和接口响应
  • Mock掉依赖的业务服务(SomeService)和用户权限对象(LoggedUser),避免依赖真实系统
  • 模拟Spring Security的认证上下文,分别测试已授权、未授权、未登录的场景

提前准备:测试依赖

确保你的pom.xml(或build.gradle)里包含这些测试依赖:

<!-- Spring Boot 基础测试依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<!-- Spring Security 测试支持 -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

具体测试代码实现

1. 测试类基础配置

用@WebMvcTest来只加载Controller相关的上下文,轻量高效;同时用@MockBean替换真实的依赖为Mock对象:

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.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;

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.*;

@WebMvcTest(SomeRestController.class)
public class SomeRestControllerTest {

    @Autowired
    private MockMvc mockMvc; // 用来模拟HTTP请求

    @MockBean
    private SomeService someService; // Mock业务服务,隔离真实业务逻辑
    @MockBean
    private LoggedUser loggedUser; // Mock当前用户对象,控制权限返回
}

2. 测试「有权限用户正常访问」场景

当用户权限允许时,接口应该正常返回业务数据:

@Test
@WithMockUser // 快速模拟一个已登录的认证用户
public void getSomeObject_WithValidPermission_ReturnsOk() throws Exception {
    // 1. 模拟用户权限:允许访问
    Permissions mockPerms = new Permissions();
    mockPerms.setCanGetSome(true);
    when(loggedUser.getPermissions()).thenReturn(mockPerms);

    // 2. 模拟业务服务返回的数据
    SomeObject mockResponse = new SomeObject();
    mockResponse.setId(1);
    mockResponse.setContent("Test Content");
    when(someService.getSomeObject()).thenReturn(mockResponse);

    // 3. 发起请求并验证结果
    mockMvc.perform(get("/getSome"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.content").value("Test Content"));
}

3. 测试「无权限用户访问被拒绝」场景

当权限不允许时,接口应该返回403 Forbidden:

@Test
@WithMockUser
public void getSomeObject_WithInvalidPermission_ReturnsForbidden() throws Exception {
    // 模拟用户权限:不允许访问
    Permissions mockPerms = new Permissions();
    mockPerms.setCanGetSome(false);
    when(loggedUser.getPermissions()).thenReturn(mockPerms);

    // 验证请求被拒绝
    mockMvc.perform(get("/getSome"))
            .andExpect(status().isForbidden());
}

4. 测试「未登录用户访问」场景

如果你的接口要求必须登录,未登录用户访问应该返回401 Unauthorized:

@Test
public void getSomeObject_WithoutLogin_ReturnsUnauthorized() throws Exception {
    mockMvc.perform(get("/getSome"))
            .andExpect(status().isUnauthorized());
}

关键细节说明

  • @WebMvcTest vs @SpringBootTest:前者只加载Controller和相关配置,测试速度更快,适合单元测试;后者加载全量上下文,适合集成测试,这里用前者就足够了。
  • 不用Mock CanGetSome:这个组件是我们要测试的权限逻辑一部分,Spring会自动注入它,我们只需要Mock它依赖的LoggedUser,就能真实触发它的isValid()校验逻辑,确保测试的准确性。
  • @WithMockUser的灵活用法:如果需要模拟特定用户名、角色,可以用@WithMockUser(username = "testUser", roles = {"USER"}),满足更复杂的认证场景。

内容的提问来源于stack exchange,提问作者Kamil W

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:54:19