unit-test-security-authorization
Provides patterns for unit testing Spring Security with `@PreAuthorize`, `@Secured`, `@RolesAllowed`. Validates role-based access control and author…
它会碰到什么
这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。
技能内容
Unit Testing Security and Authorization
Overview
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.
When to Use
Use this skill when:
- Testing
@PreAuthorizeand@Securedmethod-level security - Testing role-based access control (RBAC)
- Testing custom permission evaluators
- Verifying access denied scenarios
- Testing authorization with authenticated principals
- Want fast authorization tests without full Spring Security context
Instructions
Follow these steps to test Spring Security authorization:
1. Set Up Security Testing Dependencies
Add spring-security-test to your test dependencies:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
2. Enable Method Security in Test Configuration
@Configuration
@EnableMethodSecurity
class TestSecurityConfig { }
3. Test with @WithMockUser
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminAccess() {
assertThatCode(() -> service.deleteUser(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserAccess() {
assertThatThrownBy(() -> service.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
4. Test Custom Permission Evaluators
@Test
void shouldGrantPermissionToOwner() {
Authentication auth = new UsernamePasswordAuthenticationToken(
"alice", null, List.of(new SimpleGrantedAuthority("ROLE_USER"))
);
Document doc = new Document(1L, "Test", new User("alice"));
boolean result = evaluator.hasPermission(auth, doc, "WRITE");
assertThat(result).isTrue();
}
5. Validate Security is Active
If tests pass unexpectedly, add this assertion to verify security is enforced:
@Test
void shouldRejectUnauthorizedWhenSecurityEnabled() {
assertThatThrownBy(() -> service.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
Quick Reference
| Annotation | Description | Example |
|------------|-------------|---------|
| @PreAuthorize | Pre-invocation authorization | @PreAuthorize("hasRole('ADMIN')") |
| @PostAuthorize | Post-invocation authorization | @PostAuthorize("returnObject.owner == authentication.name") |
| @Secured | Simple role-based security | @Secured("ROLE_ADMIN") |
| @RolesAllowed | JSR-250 standard | @RolesAllowed({"ADMIN", "MANAGER"}) |
| @WithMockUser | Test annotation | @WithMockUser(roles = "ADMIN") |
Examples
Basic @PreAuthorize Test
@Service
public class UserService {
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// delete logic
}
}
// Test
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToDeleteUser() {
assertThatCode(() -> service.deleteUser(1L))
.doesNotThrowAnyException();
}
@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromDeletingUser() {
assertThatThrownBy(() -> service.deleteUser(1L))
.isInstanceOf(AccessDeniedException.class);
}
Expression-Based Security Test
@PreAuthorize("#userId == authentication.principal.id")
public UserProfile getUserProfile(Long userId) {
// get profile
}
// For custom principal properties, use @WithUserDetails with a custom UserDetailsService
@Test
@WithUserDetails("alice")
void shouldAllowUserToAccessOwnProfile() {
assertThatCode(() -> service.getUserProfile(1L))
.doesNotThrowAnyException();
}
> Validation tip: If a security test passes unexpectedly, verify that @EnableMethodSecurity is active on the test configuration — a missing annotation causes all @PreAuthorize checks to be bypassed silently.
See [references/basic-testing.md](references/basic-testing.md) for more basic patterns and [references/advanced-authorization.md](references/advanced-authorization.md) for complex expressions and custom evaluators.
Best Practices
- Use
@WithMockUserfor setting authenticated user context - Test both allow and deny cases for each security rule
- Test with different roles to verify role-based decisions
- Test expression-based security comprehensively
- Mock external dependencies (permission evaluators, etc.)
- Test anonymous access separately from authenticated access
- Use
@EnableGlobalMethodSecurityin configuration for method-level security
Common Pitfalls
- Forgetting to enable method security in test configuration
- Not testing both allow and deny scenarios
- Testing framework code instead of authorization logic
- Not handling null authentication in tests
- Mixing authentication and authorization tests unnecessarily
Constraints and Warnings
- Method security requires proxy:
@PreAuthorizeworks via proxies; direct method calls bypass security @EnableGlobalMethodSecurity: Must be enabled for@PreAuthorize,@Securedto work- Role prefix: Spring adds "ROLE_" prefix automatically; use
hasRole('ADMIN')nothasRole('ROLE_ADMIN') - Authentication context: Security context is thread-local; be careful with async tests
@WithMockUserlimitations: Creates a simple Authentication; complex auth scenarios need custom setup- SpEL expressions: Complex SpEL in
@PreAuthorizecan be difficult to debug; test thoroughly - Performance impact: Method security adds overhead; consider security at layer boundaries
References
Setup and Configuration
- [references/setup.md](references/setup.md) - Maven/Gradle dependencies and security configuration
Testing Patterns
- [references/basic-testing.md](references/basic-testing.md) - Basic patterns for
@PreAuthorize,@Secured, MockMvc testing, and parameterized tests
Advanced Topics
- [references/advanced-authorization.md](references/advanced-authorization.md) - Expression-based authorization, custom permission evaluators, SpEL expressions
Complete Examples
- [references/complete-examples.md](references/complete-examples.md) - Before/after examples showing transition from manual to declarative security
想直接用这个技能?
本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。
它属于哪个仓库
plugins/developer-kit-java/skills/unit-test-security-authorization/SKILL.md