Skip to main content Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/ForceInjection/domain-driven-design-skills --skill symfony-api-platform-security명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... Conduct deep academic research for philosophy, neuroscience, cognitive science, and theoretical computer science (computability, complexity, AI theory, logic). Use when user asks to: research academic topics, find scholarly papers, conduct literature reviews, analyze citations, synthesize research findings, explore philosophical arguments, investigate consciousness/cognition, study computability/decidability/Turing machines, or analyze academic debates. Triggers on: 'research papers', 'literature review', 'academic sources', 'scholarly articles', 'philosophy of mind', 'computability theory', 'neuroscience studies', 'find papers on', 'what does the research say'.
name symfony:api-platform-security description Secure API Platform resources with security expressions, voters, and operation-level access control
API Platform Security
Operation-Level Security
Basic Security Expressions
<?php
use ApiPlatform \Metadata \ApiResource ;
use ApiPlatform \Metadata \Delete ;
use ApiPlatform \Metadata \Get ;
use ApiPlatform \Metadata \GetCollection ;
use ApiPlatform \Metadata \Patch ;
use ApiPlatform \Metadata \Post ;
use ApiPlatform \Metadata \Put ;
#[ApiResource (
operations : [
// Public read access
new GetCollection (),
new (),
// Authenticated users can create
(
: ,
: ,
),
// Only owner or admin can update
(
: ,
: ,
),
(
: ,
),
// Only admin can delete
(
: ,
: ,
),
],
)
{
}
Get
new
Post
security
"is_granted('ROLE_USER')"
securityMessage
'You must be logged in to create posts.'
new
Put
security
"is_granted('ROLE_ADMIN') or object.getAuthor() == user"
securityMessage
'You can only edit your own posts.'
new
Patch
security
"is_granted('ROLE_ADMIN') or object.getAuthor() == user"
new
Delete
security
"is_granted('ROLE_ADMIN')"
securityMessage
'Only administrators can delete posts.'
]
class Post
Using Voters #[ApiResource (
operations : [
new Get (
security : "is_granted('POST_VIEW', object)" ,
),
new Put (
security : "is_granted('POST_EDIT', object)" ,
securityMessage : 'You cannot edit this post.' ,
),
new Delete (
security : "is_granted('POST_DELETE', object)" ,
),
],
)]
class Post { }
Security Post-Denormalization Check security after input is processed:
#[ApiResource (
operations : [
new Post (
// Check before processing
security : "is_granted('ROLE_USER')" ,
// Check after input is bound to object
securityPostDenormalize : "is_granted('POST_CREATE', object)" ,
securityPostDenormalizeMessage : 'You cannot create this type of post.' ,
),
],
)]
class Post { }
Useful when security depends on the input data itself.
Security Expressions Reference
security: "is_granted('ROLE_USER')"
security: "is_granted('ROLE_ADMIN')"
security: "user == object.getOwner()"
security: "object.getAuthor().getId() == user.getId()"
security: "object.isPublished() or object.getAuthor() == user"
security: "object.getStatus() == 'draft' and object.getAuthor() == user"
security: "is_granted('EDIT', object)"
security: "is_granted('VIEW', object)"
security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and object.getAuthor() == user)"
security: "is_granted('ROLE_ADMIN') or request.get('category') != 'restricted'"
Collection Security
Filter Collections by User <?php
namespace App \Doctrine ;
use ApiPlatform \Doctrine \Orm \Extension \QueryCollectionExtensionInterface ;
use ApiPlatform \Doctrine \Orm \Util \QueryNameGeneratorInterface ;
use ApiPlatform \Metadata \Operation ;
use App \Entity \Post ;
use Doctrine \ORM \QueryBuilder ;
use Symfony \Bundle \SecurityBundle \Security ;
final class CurrentUserExtension implements QueryCollectionExtensionInterface
{
public function __construct (
private Security $security ,
) {}
public function applyToCollection (
QueryBuilder $queryBuilder ,
QueryNameGeneratorInterface $queryNameGenerator ,
string $resourceClass ,
?Operation $operation = null ,
array $context = []
): void {
if ($resourceClass !== Post ::class ) {
return ;
}
if ($this ->security->isGranted ('ROLE_ADMIN' )) {
return ;
}
$user = $this ->security->getUser ();
$alias = $queryBuilder ->getRootAliases ()[0 ];
if ($user ) {
$queryBuilder
->andWhere (sprintf (
'%s.isPublished = true OR %s.author = :currentUser' ,
$alias ,
$alias
))
->setParameter ('currentUser' , $user );
} else {
$queryBuilder
->andWhere (sprintf ('%s.isPublished = true' , $alias ));
}
}
}
Filter Item Queries use ApiPlatform \Doctrine \Orm \Extension \QueryItemExtensionInterface ;
final class CurrentUserExtension implements
QueryCollectionExtensionInterface ,
QueryItemExtensionInterface
{
public function applyToItem (
QueryBuilder $queryBuilder ,
QueryNameGeneratorInterface $queryNameGenerator ,
string $resourceClass ,
array $identifiers ,
?Operation $operation = null ,
array $context = []
): void {
$this ->addWhere ($queryBuilder , $resourceClass );
}
public function applyToCollection ( ): void
{
$this ->addWhere ($queryBuilder , $resourceClass );
}
private function addWhere (QueryBuilder $queryBuilder , string $resourceClass ): void
{
}
}
Property-Level Security Hide fields based on permissions:
<?php
use Symfony \Component \Serializer \Attribute \Groups ;
class User
{
#[Groups (['user:read' , 'admin:read' ])]
private ?int $id = null ;
#[Groups (['user:read' , 'admin:read' ])]
private string $name ;
#[Groups (['user:owner' , 'admin:read' ])]
private string $email ;
#[Groups (['admin:read' ])]
private array $roles ;
private string $password ;
}
With context builder for dynamic groups:
<?php
final class UserContextBuilder implements SerializerContextBuilderInterface
{
public function createFromRequest (Request $request , bool $normalization , ?array $extractedAttributes = null ): array
{
$context = $this ->decorated->createFromRequest ($request , $normalization , $extractedAttributes );
if ($this ->security->isGranted ('ROLE_ADMIN' )) {
$context ['groups' ][] = 'admin:read' ;
}
$resourceId = $request ->attributes->get ('id' );
$currentUser = $this ->security->getUser ();
if ($currentUser && $currentUser ->getId () == $resourceId ) {
$context ['groups' ][] = 'user:owner' ;
}
return $context ;
}
}
JWT Authentication
security:
firewalls:
api:
pattern: ^/api
stateless: true
jwt: ~
access_control:
- { path: ^/api/login , roles: PUBLIC_ACCESS }
- { path: ^/api/docs , roles: PUBLIC_ACCESS }
- { path: ^/api , roles: IS_AUTHENTICATED_FULLY }
Rate Limiting use Symfony \Component \RateLimiter \Attribute \RateLimit ;
#[ApiResource (
operations : [
new Post (
security : "is_granted('ROLE_USER')" ,
),
],
)]
#[RateLimit (limit : 10 , interval : '1 minute' )]
class Comment { }
Best Practices
Use voters for complex authorization logic
Filter collections with Doctrine extensions
Fail secure - deny by default
Clear error messages - help users understand
Test security - verify both grant and deny cases
Audit sensitive operations - log access attempts