权限测试应模拟真实认证上下文而非禁用安全机制:用@withmockuser测试角色策略,@withmockjwt模拟oauth2令牌,保留securityfilterchain并断言响应状态与内容。

权限测试报错,往往不是代码写错了,而是测试方式没对上安全机制的运行逻辑。直接禁用 Spring Security 或跳过认证流程,看似能跑通,实则让权限规则彻底失效——你测的不是“有权限时能做什么”,而是“没安全时能做什么”。真正有效的做法是模拟真实认证上下文,让权限校验照常执行,只是把外部依赖(如 Auth0、Keycloak)换成可控的 Mock。
用 @WithMockUser 精准控制基础角色权限
适合验证简单角色策略(如 .hasRole("ADMIN") 或 .hasAuthority("READ_DATA"))。它不查数据库,也不走真实登录流程,而是直接在 SecurityContext 中注入一个预设的 Authentication 对象。
- 测试管理员访问:加注解
@WithMockUser(roles = "ADMIN"),请求自动携带 ADMIN 角色 - 测试无权限拒绝:用
@WithMockUser(roles = "USER")访问仅限 ADMIN 的接口,应返回 403 - 避免硬编码:可在测试类顶部统一设置默认用户,减少重复
用 @WithMockJwt 模拟 OAuth2 实际令牌行为
当系统已启用 spring-boot-starter-oauth2-resource-server,JWT 校验和 scope/authority 映射是关键路径。此时 @WithMockUser 不再适用,因为它不生成真实 JWT 结构,也无法触发 JwtAuthenticationConverter 的声明解析逻辑。
- 使用
@WithMockJwt(Spring Security Test 5.7+)或@WithMockJwtAuth(社区常用别名),可指定 claims 如scope、aud、iss - 例如:带
"scope": "read:data write:config"的令牌,应能通过.hasAuthority("SCOPE_read:data")校验 - 测试 token 过期、签名无效等异常场景?需配合自定义
SecurityContextFactory注入伪造 JWT
绕过认证 ≠ 绕过权限,别误删 SecurityFilterChain
有些测试会用 @TestConfiguration 替换掉 SecurityFilterChain Bean,或者加 @EnableWebSecurity(debug = false) 关闭全部过滤器。这会导致:
- 所有
authorizeHttpRequests()配置完全不生效 - 无法发现
.requestMatchers("/api/**").authenticated()是否漏配 - 上线后因权限配置错误导致越权访问,测试阶段毫无预警
正确姿势是保留完整过滤器链,只替换认证源头(如把 BearerTokenResolver 换成内存令牌解析器),确保权限决策路径完整走通。
断言响应状态码与响应体,验证权限逻辑是否真起作用
光看能不能进接口不够,要确认权限控制点是否按预期拦截或放行:
- 匿名请求访问
/actuator/health→ 断言status().isOk() - 普通用户请求
/api/admin/config→ 断言status().isForbidden()并检查响应体含"access_denied" - 带
SCOPE_delete:user的 JWT 请求删除接口 → 断言status().isOk()且返回值符合业务预期
用 MockMvc + jsonPath 组合断言,比只看 HTTP 状态更可靠。











