unit-test-security-authorization by giuseppe-trisciuoglio/developer-kit
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill unit-test-security-authorization本技能提供了使用 @PreAuthorize、@Secured、@RolesAllowed 和自定义权限评估器对 Spring Security 授权逻辑进行单元测试的模式。它涵盖了测试基于角色的访问控制(RBAC)、基于表达式的授权、自定义权限评估器,以及在没有完整 Spring Security 上下文的情况下验证访问被拒绝的场景。
在以下情况下使用此技能:
@PreAuthorize 和 @Secured 方法级安全性按照以下步骤测试 Spring Security 授权:
将 spring-security-test 添加到您的测试依赖项中,同时包括 JUnit 5 和 AssertJ。
使用 @EnableGlobalMethodSecurity(prePostEnabled = true) 来激活 注解。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
@PreAuthorize@WithMockUser 创建测试应用 @WithMockUser 注解来模拟具有特定角色和权限的已认证用户。
对于每个安全规则,测试授权用户可以访问该方法,未授权用户收到 AccessDeniedException。
验证复杂表达式(如 authentication.principal.username == #owner)是否正确工作。
通过创建 Authentication 对象并直接调用 hasPermission 来对自定义 PermissionEvaluator 实现进行单元测试。
模拟外部依赖项,并验证安全检查不会干扰业务逻辑。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
dependencies {
implementation("org.springframework.boot:spring-boot-starter-security")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.security:spring-security-test")
}
@PreAuthorize// 带有安全注解的服务
@Service
public class UserService {
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// 删除逻辑
}
@PreAuthorize("hasRole('USER')")
public User getCurrentUser() {
// 获取用户逻辑
}
@PreAuthorize("hasAnyRole('ADMIN', 'MANAGER')")
public List<User> listAllUsers() {
// 列表逻辑
}
}
// 单元测试
import org.junit.jupiter.api.Test;
import org.springframework.security.test.context.support.WithMockUser;
import static org.assertj.core.api.Assertions.*;
class UserServiceSecurityTest {
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToDeleteUser() {
UserService service = new UserService();
assertThatCode(() -> service.deleteUser(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromDeletingUser() {
UserService service = new UserService();
assertThatThrownBy(() -> service.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminAndManagerToListUsers() {
UserService service = new UserService();
assertThatCode(() -> service.listAllUsers())
.doesNotThrowAnyException();
}
@Test
void shouldDenyAnonymousUserAccess() {
UserService service = new UserService();
assertThatThrownBy(() -> service.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
}
@Secured 注解@Service
public class OrderService {
@Secured("ROLE_ADMIN")
public Order approveOrder(Long orderId) {
// 批准逻辑
}
@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
public List<Order> getOrders() {
// 获取订单
}
}
class OrderSecurityTest {
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToApproveOrder() {
OrderService service = new OrderService();
assertThatCode(() -> service.approveOrder(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromApprovingOrder() {
OrderService service = new OrderService();
assertThatThrownBy(() -> service.approveOrder(1L))
.isInstanceOf(AccessDeniedException.class);
}
}
@RestController
@RequestMapping("/api/admin")
public class AdminController {
@GetMapping("/users")
@PreAuthorize("hasRole('ADMIN')")
public List<UserDto> listAllUsers() {
// 逻辑
}
@DeleteMapping("/users/{id}")
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(@PathVariable Long id) {
// 删除逻辑
}
}
// 使用 MockMvc 进行测试
import org.springframework.security.test.context.support.WithMockUser;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
class AdminControllerSecurityTest {
private MockMvc mockMvc;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders
.standaloneSetup(new AdminController())
.apply(springSecurity())
.build();
}
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToListUsers() throws Exception {
mockMvc.perform(get("/api/admin/users"))
.andExpect(status().isOk());
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromListingUsers() throws Exception {
mockMvc.perform(get("/api/admin/users"))
.andExpect(status().isForbidden());
}
@Test
void shouldDenyAnonymousAccessToAdminEndpoint() throws Exception {
mockMvc.perform(get("/api/admin/users"))
.andExpect(status().isUnauthorized());
}
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToDeleteUser() throws Exception {
mockMvc.perform(delete("/api/admin/users/1"))
.andExpect(status().isOk());
}
}
@Service
public class DocumentService {
@PreAuthorize("hasRole('ADMIN') or authentication.principal.username == #owner")
public Document getDocument(String owner, Long docId) {
// 获取文档
}
@PreAuthorize("hasPermission(#docId, 'Document', 'WRITE')")
public void updateDocument(Long docId, String content) {
// 更新逻辑
}
@PreAuthorize("#userId == authentication.principal.id")
public UserProfile getUserProfile(Long userId) {
// 获取配置文件
}
}
class ExpressionBasedSecurityTest {
@Test
@WithMockUser(username = "alice", roles = "ADMIN")
void shouldAllowAdminToAccessAnyDocument() {
DocumentService service = new DocumentService();
assertThatCode(() -> service.getDocument("bob", 1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(username = "alice")
void shouldAllowOwnerToAccessOwnDocument() {
DocumentService service = new DocumentService();
assertThatCode(() -> service.getDocument("alice", 1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(username = "alice")
void shouldDenyUserAccessToOtherUserDocument() {
DocumentService service = new DocumentService();
assertThatThrownBy(() -> service.getDocument("bob", 1L))
.isInstanceOf(AccessDeniedException.class);
}
@Test
@WithMockUser(username = "alice", id = "1")
void shouldAllowUserToAccessOwnProfile() {
DocumentService service = new DocumentService();
assertThatCode(() -> service.getUserProfile(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(username = "alice", id = "1")
void shouldDenyUserAccessToOtherProfile() {
DocumentService service = new DocumentService();
assertThatThrownBy(() -> service.getUserProfile(999L))
.isInstanceOf(AccessDeniedException.class);
}
}
// 自定义权限评估器
@Component
public class DocumentPermissionEvaluator implements PermissionEvaluator {
private final DocumentRepository documentRepository;
public DocumentPermissionEvaluator(DocumentRepository documentRepository) {
this.documentRepository = documentRepository;
}
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
if (authentication == null) return false;
Document document = (Document) targetDomainObject;
String userUsername = authentication.getName();
return document.getOwner().getUsername().equals(userUsername) ||
userHasRole(authentication, "ADMIN");
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
if (authentication == null) return false;
if (!"Document".equals(targetType)) return false;
Document document = documentRepository.findById((Long) targetId).orElse(null);
if (document == null) return false;
return hasPermission(authentication, document, permission);
}
private boolean userHasRole(Authentication authentication, String role) {
return authentication.getAuthorities().stream()
.anyMatch(auth -> auth.getAuthority().equals("ROLE_" + role));
}
}
// 自定义评估器的单元测试
class DocumentPermissionEvaluatorTest {
private DocumentPermissionEvaluator evaluator;
private DocumentRepository documentRepository;
private Authentication adminAuth;
private Authentication userAuth;
private Document document;
@BeforeEach
void setUp() {
documentRepository = mock(DocumentRepository.class);
evaluator = new DocumentPermissionEvaluator(documentRepository);
document = new Document(1L, "Test Doc", new User("alice"));
adminAuth = new UsernamePasswordAuthenticationToken(
"admin",
null,
List.of(new SimpleGrantedAuthority("ROLE_ADMIN"))
);
userAuth = new UsernamePasswordAuthenticationToken(
"alice",
null,
List.of(new SimpleGrantedAuthority("ROLE_USER"))
);
}
@Test
void shouldGrantPermissionToDocumentOwner() {
boolean hasPermission = evaluator.hasPermission(userAuth, document, "WRITE");
assertThat(hasPermission).isTrue();
}
@Test
void shouldDenyPermissionToNonOwner() {
Authentication otherUserAuth = new UsernamePasswordAuthenticationToken(
"bob",
null,
List.of(new SimpleGrantedAuthority("ROLE_USER"))
);
boolean hasPermission = evaluator.hasPermission(otherUserAuth, document, "WRITE");
assertThat(hasPermission).isFalse();
}
@Test
void shouldGrantPermissionToAdmin() {
boolean hasPermission = evaluator.hasPermission(adminAuth, document, "WRITE");
assertThat(hasPermission).isTrue();
}
@Test
void shouldDenyNullAuthentication() {
boolean hasPermission = evaluator.hasPermission(null, document, "WRITE");
assertThat(hasPermission).isFalse();
}
}
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
class RoleBasedAccessTest {
private AdminService service;
@BeforeEach
void setUp() {
service = new AdminService();
}
@ParameterizedTest
@ValueSource(strings = {"ADMIN", "SUPER_ADMIN", "SYSTEM"})
@WithMockUser(roles = "ADMIN")
void shouldAllowPrivilegedRolesToDeleteUser(String role) {
assertThatCode(() -> service.deleteUser(1L))
.doesNotThrowAnyException();
}
@ParameterizedTest
@ValueSource(strings = {"USER", "GUEST", "READONLY"})
void shouldDenyUnprivilegedRolesToDeleteUser(String role) {
assertThatThrownBy(() -> service.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
}
@WithMockUser 来设置已认证用户上下文@EnableGlobalMethodSecurity 用于方法级安全性@PreAuthorize 通过代理工作;直接方法调用会绕过安全性@EnableGlobalMethodSecurity:必须启用才能使 @PreAuthorize、@Secured 工作@WithMockUser 限制:创建简单的 Authentication;复杂的认证场景需要自定义设置@PreAuthorize 中的复杂 SpEL 可能难以调试;需要彻底测试@Service
public class AdminService {
public void deleteUser(Long userId) {
// 没有安全检查的删除逻辑
}
}
@Service
public class AdminService {
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// 删除逻辑
}
}
// 测试
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToDeleteUser() {
assertThatCode(() -> adminService.deleteUser(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromDeletingUser() {
assertThatThrownBy(() -> adminService.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
if (user.hasRole("ADMIN")) {
service.deleteUser(userId);
}
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// 仅业务逻辑,安全性是声明式的
}
// 测试验证安全执行
@Test
@WithMockUser(roles = "ADMIN")
void shouldExecuteDelete() {
service.deleteUser(1L);
verify(repository).deleteById(1L);
}
AccessDeniedException 未抛出:确保配置了 @EnableGlobalMethodSecurity(prePostEnabled = true)。
@WithMockUser 不工作:验证 Spring Security 测试依赖项是否在类路径上。
自定义 PermissionEvaluator 未调用:检查 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)。
每周安装次数
336
仓库
GitHub 星标数
173
首次出现
2026年2月3日
安全审计
已安装于
claude-code267
gemini-cli254
opencode253
cursor250
codex248
github-copilot234
This skill provides patterns for unit testing Spring Security authorization logic using @PreAuthorize, @Secured, @RolesAllowed, and custom permission evaluators. It covers testing role-based access control (RBAC), expression-based authorization, custom permission evaluators, and verifying access denied scenarios without full Spring Security context.
Use this skill when:
@PreAuthorize and @Secured method-level securityFollow these steps to test Spring Security authorization:
Add spring-security-test to your test dependencies along with JUnit 5 and AssertJ.
Use @EnableGlobalMethodSecurity(prePostEnabled = true) to activate @PreAuthorize annotations.
@WithMockUserApply @WithMockUser annotation to simulate authenticated users with specific roles and authorities.
For each security rule, test that authorized users can access the method and unauthorized users receive AccessDeniedException.
Verify complex expressions like authentication.principal.username == #owner work correctly.
Unit test custom PermissionEvaluator implementations by creating Authentication objects and calling hasPermission directly.
Mock external dependencies and verify that security checks don't interfere with business logic.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
dependencies {
implementation("org.springframework.boot:spring-boot-starter-security")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.security:spring-security-test")
}
@PreAuthorize// Service with security annotations
@Service
public class UserService {
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// delete logic
}
@PreAuthorize("hasRole('USER')")
public User getCurrentUser() {
// get user logic
}
@PreAuthorize("hasAnyRole('ADMIN', 'MANAGER')")
public List<User> listAllUsers() {
// list logic
}
}
// Unit test
import org.junit.jupiter.api.Test;
import org.springframework.security.test.context.support.WithMockUser;
import static org.assertj.core.api.Assertions.*;
class UserServiceSecurityTest {
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToDeleteUser() {
UserService service = new UserService();
assertThatCode(() -> service.deleteUser(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromDeletingUser() {
UserService service = new UserService();
assertThatThrownBy(() -> service.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminAndManagerToListUsers() {
UserService service = new UserService();
assertThatCode(() -> service.listAllUsers())
.doesNotThrowAnyException();
}
@Test
void shouldDenyAnonymousUserAccess() {
UserService service = new UserService();
assertThatThrownBy(() -> service.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
}
@Secured Annotation@Service
public class OrderService {
@Secured("ROLE_ADMIN")
public Order approveOrder(Long orderId) {
// approval logic
}
@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
public List<Order> getOrders() {
// get orders
}
}
class OrderSecurityTest {
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToApproveOrder() {
OrderService service = new OrderService();
assertThatCode(() -> service.approveOrder(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromApprovingOrder() {
OrderService service = new OrderService();
assertThatThrownBy(() -> service.approveOrder(1L))
.isInstanceOf(AccessDeniedException.class);
}
}
@RestController
@RequestMapping("/api/admin")
public class AdminController {
@GetMapping("/users")
@PreAuthorize("hasRole('ADMIN')")
public List<UserDto> listAllUsers() {
// logic
}
@DeleteMapping("/users/{id}")
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(@PathVariable Long id) {
// delete logic
}
}
// Testing with MockMvc
import org.springframework.security.test.context.support.WithMockUser;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
class AdminControllerSecurityTest {
private MockMvc mockMvc;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders
.standaloneSetup(new AdminController())
.apply(springSecurity())
.build();
}
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToListUsers() throws Exception {
mockMvc.perform(get("/api/admin/users"))
.andExpect(status().isOk());
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromListingUsers() throws Exception {
mockMvc.perform(get("/api/admin/users"))
.andExpect(status().isForbidden());
}
@Test
void shouldDenyAnonymousAccessToAdminEndpoint() throws Exception {
mockMvc.perform(get("/api/admin/users"))
.andExpect(status().isUnauthorized());
}
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToDeleteUser() throws Exception {
mockMvc.perform(delete("/api/admin/users/1"))
.andExpect(status().isOk());
}
}
@Service
public class DocumentService {
@PreAuthorize("hasRole('ADMIN') or authentication.principal.username == #owner")
public Document getDocument(String owner, Long docId) {
// get document
}
@PreAuthorize("hasPermission(#docId, 'Document', 'WRITE')")
public void updateDocument(Long docId, String content) {
// update logic
}
@PreAuthorize("#userId == authentication.principal.id")
public UserProfile getUserProfile(Long userId) {
// get profile
}
}
class ExpressionBasedSecurityTest {
@Test
@WithMockUser(username = "alice", roles = "ADMIN")
void shouldAllowAdminToAccessAnyDocument() {
DocumentService service = new DocumentService();
assertThatCode(() -> service.getDocument("bob", 1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(username = "alice")
void shouldAllowOwnerToAccessOwnDocument() {
DocumentService service = new DocumentService();
assertThatCode(() -> service.getDocument("alice", 1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(username = "alice")
void shouldDenyUserAccessToOtherUserDocument() {
DocumentService service = new DocumentService();
assertThatThrownBy(() -> service.getDocument("bob", 1L))
.isInstanceOf(AccessDeniedException.class);
}
@Test
@WithMockUser(username = "alice", id = "1")
void shouldAllowUserToAccessOwnProfile() {
DocumentService service = new DocumentService();
assertThatCode(() -> service.getUserProfile(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(username = "alice", id = "1")
void shouldDenyUserAccessToOtherProfile() {
DocumentService service = new DocumentService();
assertThatThrownBy(() -> service.getUserProfile(999L))
.isInstanceOf(AccessDeniedException.class);
}
}
// Custom permission evaluator
@Component
public class DocumentPermissionEvaluator implements PermissionEvaluator {
private final DocumentRepository documentRepository;
public DocumentPermissionEvaluator(DocumentRepository documentRepository) {
this.documentRepository = documentRepository;
}
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
if (authentication == null) return false;
Document document = (Document) targetDomainObject;
String userUsername = authentication.getName();
return document.getOwner().getUsername().equals(userUsername) ||
userHasRole(authentication, "ADMIN");
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
if (authentication == null) return false;
if (!"Document".equals(targetType)) return false;
Document document = documentRepository.findById((Long) targetId).orElse(null);
if (document == null) return false;
return hasPermission(authentication, document, permission);
}
private boolean userHasRole(Authentication authentication, String role) {
return authentication.getAuthorities().stream()
.anyMatch(auth -> auth.getAuthority().equals("ROLE_" + role));
}
}
// Unit test for custom evaluator
class DocumentPermissionEvaluatorTest {
private DocumentPermissionEvaluator evaluator;
private DocumentRepository documentRepository;
private Authentication adminAuth;
private Authentication userAuth;
private Document document;
@BeforeEach
void setUp() {
documentRepository = mock(DocumentRepository.class);
evaluator = new DocumentPermissionEvaluator(documentRepository);
document = new Document(1L, "Test Doc", new User("alice"));
adminAuth = new UsernamePasswordAuthenticationToken(
"admin",
null,
List.of(new SimpleGrantedAuthority("ROLE_ADMIN"))
);
userAuth = new UsernamePasswordAuthenticationToken(
"alice",
null,
List.of(new SimpleGrantedAuthority("ROLE_USER"))
);
}
@Test
void shouldGrantPermissionToDocumentOwner() {
boolean hasPermission = evaluator.hasPermission(userAuth, document, "WRITE");
assertThat(hasPermission).isTrue();
}
@Test
void shouldDenyPermissionToNonOwner() {
Authentication otherUserAuth = new UsernamePasswordAuthenticationToken(
"bob",
null,
List.of(new SimpleGrantedAuthority("ROLE_USER"))
);
boolean hasPermission = evaluator.hasPermission(otherUserAuth, document, "WRITE");
assertThat(hasPermission).isFalse();
}
@Test
void shouldGrantPermissionToAdmin() {
boolean hasPermission = evaluator.hasPermission(adminAuth, document, "WRITE");
assertThat(hasPermission).isTrue();
}
@Test
void shouldDenyNullAuthentication() {
boolean hasPermission = evaluator.hasPermission(null, document, "WRITE");
assertThat(hasPermission).isFalse();
}
}
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
class RoleBasedAccessTest {
private AdminService service;
@BeforeEach
void setUp() {
service = new AdminService();
}
@ParameterizedTest
@ValueSource(strings = {"ADMIN", "SUPER_ADMIN", "SYSTEM"})
@WithMockUser(roles = "ADMIN")
void shouldAllowPrivilegedRolesToDeleteUser(String role) {
assertThatCode(() -> service.deleteUser(1L))
.doesNotThrowAnyException();
}
@ParameterizedTest
@ValueSource(strings = {"USER", "GUEST", "READONLY"})
void shouldDenyUnprivilegedRolesToDeleteUser(String role) {
assertThatThrownBy(() -> service.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
}
@WithMockUser for setting authenticated user context@EnableGlobalMethodSecurity in configuration for method-level security@PreAuthorize works via proxies; direct method calls bypass security@EnableGlobalMethodSecurity: Must be enabled for @PreAuthorize, @Secured to work@WithMockUser limitations: Creates a simple Authentication; complex auth scenarios need custom setup@PreAuthorize can be difficult to debug; test thoroughly@Service
public class AdminService {
public void deleteUser(Long userId) {
// Delete logic without security check
}
}
@Service
public class AdminService {
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// Delete logic
}
}
// Test
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToDeleteUser() {
assertThatCode(() -> adminService.deleteUser(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromDeletingUser() {
assertThatThrownBy(() -> adminService.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
if (user.hasRole("ADMIN")) {
service.deleteUser(userId);
}
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// Business logic only, security is declarative
}
// Test verifies security enforcement
@Test
@WithMockUser(roles = "ADMIN")
void shouldExecuteDelete() {
service.deleteUser(1L);
verify(repository).deleteById(1L);
}
AccessDeniedException not thrown : Ensure @EnableGlobalMethodSecurity(prePostEnabled = true) is configured.
@WithMockUser not working: Verify Spring Security test dependencies are on classpath.
Custom PermissionEvaluator not invoked : Check @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true).
Weekly Installs
336
Repository
GitHub Stars
173
First Seen
Feb 3, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
claude-code267
gemini-cli254
opencode253
cursor250
codex248
github-copilot234
代码审查最佳实践指南:完整流程、安全与性能审查清单
12,400 周安装
OpenAI音频转录技能:快速准确转录音频文件,支持说话人分离和文本导出
565 周安装
Azure Verified Modules (AVM) 认证要求详解:Terraform 模块开发规范与最佳实践
528 周安装
Oracle到PostgreSQL迁移测试项目脚手架 - 集成测试基础设施搭建指南
601 周安装
Kotlin 开发模式与最佳实践 | 构建健壮高效应用程序的惯用指南
704 周安装
Office转Markdown工具:Word/Excel/PPT/PDF一键转换,支持AI增强处理
600 周安装
Oracle到PostgreSQL迁移集成测试规划指南 | 数据库迁移测试自动化
601 周安装