unit-test-security-authorization — скилл для Claude Code: тесты
Скилл задаёт шаблоны юнит-тестов авторизации Spring Security: @PreAuthorize, @Secured, @RolesAllowed и свои permission evaluators. Пригодится, когда нужно проверить доступ по ролям без полного контекста Spring Security.
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-security-authorization -a claude-codeЧто делает unit-test-security-authorization
Скилл описывает, как писать тесты на method-level security в Spring. Внутри — шаги: подключить spring-security-test в тестовые зависимости, включить @EnableMethodSecurity в тестовой конфигурации, дальше проверять доступ через @WithMockUser с разными ролями. Есть примеры на assertThatCode и assertThatThrownBy для разрешённого и запрещённого доступа, а также разбор кастомных permission evaluators.
Отдельно разобраны выражения в аннотациях: @PreAuthorize("#userId == authentication.principal.id") и @WithUserDetails для собственного UserDetailsService. В quick reference сведены @PreAuthorize, @PostAuthorize, @Secured, @RolesAllowed и @WithMockUser с примерами. В репозитории лежат справочники по setup, базовым шаблонам, сложным выражениям и полным примерам.
Главная ловушка: если @EnableMethodSecurity на тестовой конфигурации нет, все проверки @PreAuthorize молча обходятся, и тест проходит, хотя не должен. Скилл советует добавить проверку на AccessDeniedException, чтобы убедиться, что защита вообще работает. Ещё @PreAuthorize действует через прокси, поэтому прямой вызов метода в тесте защиту обходит.
Какие задачи решает
- проверить, что
@PreAuthorizeпускает только админа - написать тест на отказ в доступе для роли USER
- протестировать свой permission evaluator на владельце документа
- убедиться, что method security вообще включена в тестах
- покрыть тестами выражения SpEL в аннотациях доступа
Примеры запросов агенту
- напиши тесты на
@PreAuthorizeдляUserService.deleteUserс ролями ADMIN и USER - проверь мой кастомный permission evaluator: владелец получает WRITE, остальные нет
- добавь тест, который падает, если
@EnableMethodSecurityне включена
Как установить unit-test-security-authorization
1Через Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-security-authorization -a claude-code2Вручную: положить файлы
~/.claude/skills/unit-test-security-authorization/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/unit-test-security-authorization/
1Через Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-security-authorization -a codex2Вручную: положить файлы
.agents/skills/unit-test-security-authorization/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-security-authorization -a cursor2Вручную: положить файлы
.cursor/skills/unit-test-security-authorization/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install giuseppe-trisciuoglio/developer-kit unit-test-security-authorization2Вручную: положить файлы
.github/skills/unit-test-security-authorization/SKILL.md1Через Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-security-authorization -a gemini-cli2Командой платформы
gemini skills install https://github.com/giuseppe-trisciuoglio/developer-kit --path plugins/developer-kit-java/skills/unit-test-security-authorizationВручную: положить файлы
.devin/skills/unit-test-security-authorization/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-security-authorization -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о unit-test-security-authorization
Как установить unit-test-security-authorization в Claude?
Выполните npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-security-authorization -a claude-code. После этого скилл появится по пути ~/.claude/skills/unit-test-security-authorization/SKILL.md.
Что делает unit-test-security-authorization?
Даёт шаблоны юнит-тестов авторизации Spring Security: @PreAuthorize, @Secured, @RolesAllowed, кастомные permission evaluators и сценарии отказа в доступе.
Почему тест на @PreAuthorize проходит, хотя доступ должен быть закрыт?
Скорее всего на тестовой конфигурации нет @EnableMethodSecurity — тогда проверки обходятся молча. Скилл советует добавить тест, ожидающий AccessDeniedException.
Исходный текст
SKILL.md · MIT
---
name: unit-test-security-authorization
description: Provides patterns for unit testing Spring Security with `@PreAuthorize`, `@Secured`, `@RolesAllowed`. Validates role-based access control and authorization policies. Use when testing security configurations and access control logic.
allowed-tools: Read, Write, Bash, Glob, Grep
---
# 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 `@PreAuthorize` and `@Secured` method-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:
```xml
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
```
### 2. Enable Method Security in Test Configuration
```java
@Configuration
@EnableMethodSecurity
class TestSecurityConfig { }
```
### 3. Test with `@WithMockUser`
```java
@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
```java
@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:
```java
@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
```java
@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
```java
@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
1. **Use `@WithMockUser`** for setting authenticated user context
2. **Test both allow and deny cases** for each security rule
3. **Test with different roles** to verify role-based decisions
4. **Test expression-based security** comprehensively
5. **Mock external dependencies** (permission evaluators, etc.)
6. **Test anonymous access separately** from authenticated access
7. **Use `@EnableGlobalMethodSecurity`** in 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**: `@PreAuthorize` works via proxies; direct method calls bypass security
- **`@EnableGlobalMethodSecurity`**: Must be enabled for `@PreAuthorize`, `@Secured` to work
- **Role prefix**: Spring adds "ROLE_" prefix automatically; use `hasRole('ADMIN')` not `hasRole('ROLE_ADMIN')`
- **Authentication context**: Security context is thread-local; be careful with async tests
- **`@WithMockUser` limitations**: Creates a simple Authentication; complex auth scenarios need custom setup
- **SpEL expressions**: Complex SpEL in `@PreAuthorize` can 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
© giuseppe-trisciuoglio · MIT · giuseppe-trisciuoglio/developer-kit