> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# PHP-Attribute für Controller

> In Laravel 13 wurden die Attribute #[Middleware], #[WithoutMiddleware] und #[Authorize] hinzugefügt. Dieser Artikel erläutert, wie Sie Middleware- und Autorisierungseinstellungen für Controller deklarativ definieren.

## Überblick

In Laravel 13 können Sie die Middleware-Zuweisung und Autorisierungsprüfungen für Controller mit PHP-Attributen deklarativ definieren. Statt der bisherigen `middleware()`-Methode oder der `can`-Middleware genügt es, Attribute direkt an Klassen oder Methoden anzubringen.

```php theme={null}
use Illuminate\Routing\Attributes\Controllers\Authorize;
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class PostController
{
    #[Middleware('subscribed')]
    #[Authorize('create', Post::class)]
    public function store(Request $request): Response
    {
        // ...
    }
}
```

<Tip>
  Alle Controller-Attribute befinden sich im Namespace `Illuminate\Routing\Attributes\Controllers`.
</Tip>

## `#[Middleware]` — Middleware zuweisen

### Anwendung auf Klassen

Wenn Sie `#[Middleware]` auf Klassenebene anbringen, wird die Middleware auf alle Aktionen dieses Controllers angewendet.

```php theme={null}
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class UserController
{
    public function index(): View { /* ... */ }
    public function show(User $user): View { /* ... */ }
    public function store(Request $request): Response { /* ... */ }
}
```

Um mehrere Middlewares anzugeben, wiederholen Sie das Attribut.

```php theme={null}
#[Middleware('auth')]
#[Middleware('verified')]
class ProfileController
{
    // ...
}
```

### Anwendung auf Methoden

Auf Methodenebene angebrachte Middleware wird mit der Middleware auf Klassenebene zusammengeführt.

```php theme={null}
#[Middleware('auth')]
class UserController
{
    // Für alle nur auth
    public function index(): View { /* ... */ }

    // Sowohl auth als auch subscribed werden angewendet
    #[Middleware('subscribed')]
    public function create(): View { /* ... */ }
}
```

### Einschränkung über `only` / `except`

Wenn Sie `only` oder `except` bei Attributen auf Klassenebene angeben, können Sie die betroffenen Methoden einschränken.

```php theme={null}
#[Middleware('auth')]
#[Middleware('subscribed', only: ['create', 'store', 'edit', 'update'])]
class ArticleController
{
    // Nur auth
    public function index(): View { /* ... */ }
    public function show(Article $article): View { /* ... */ }

    // auth + subscribed
    public function create(): View { /* ... */ }
    public function store(Request $request): Response { /* ... */ }
    public function edit(Article $article): View { /* ... */ }
    public function update(Request $request, Article $article): Response { /* ... */ }

    // Nur auth (entspricht dem Ausschluss durch except)
    public function destroy(Article $article): Response { /* ... */ }
}
```

### Closure-Middleware

Für Attribute lassen sich auch Closures verwenden. Das ist praktisch, wenn Sie die Logik inline schreiben möchten.

```php theme={null}
use Closure;
use Illuminate\Http\Request;
use Illuminate\Routing\Attributes\Controllers\Middleware;

class ReportController
{
    #[Middleware(static function (Request $request, Closure $next) {
        if (! $request->user()->hasRole('analyst')) {
            abort(403);
        }

        return $next($request);
    })]
    public function generate(): Response
    {
        // ...
    }
}
```

### Vergleich mit der klassischen `middleware()`-Methode

```php theme={null}
// Klassische Schreibweise (Implementierung des HasMiddleware-Interface)
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;

class UserController implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            'auth',
            new Middleware('log', only: ['index']),
            new Middleware('subscribed', except: ['store']),
        ];
    }
}

// Schreibweise mit Attributen
#[Middleware('auth')]
#[Middleware('log', only: ['index'])]
#[Middleware('subscribed', except: ['store'])]
class UserController
{
    // Implementierung von HasMiddleware nicht erforderlich
}
```

<Info>
  Wenn Sie Attribute verwenden, müssen Sie das Interface `HasMiddleware` nicht implementieren. Da eine Mischung aus `middleware()`-Methode und Attributen jedoch zu unerwartetem Verhalten führen kann, empfehlen wir, sich auf eine der beiden Varianten festzulegen.
</Info>

## `#[WithoutMiddleware]` — Middleware ausschließen

Schließt Middleware, die auf Klassenebene angewendet wurde, für bestimmte Methoden oder die gesamte Klasse aus.

### Anwendung auf Methoden

```php theme={null}
use App\Http\Middleware\EnsureTokenIsValid;
use Illuminate\Routing\Attributes\Controllers\Middleware;
use Illuminate\Routing\Attributes\Controllers\WithoutMiddleware;

#[Middleware('auth')]
#[Middleware(EnsureTokenIsValid::class)]
class ApiController
{
    // auth und EnsureTokenIsValid werden angewendet
    public function show(Resource $resource): JsonResponse { /* ... */ }

    // auth wird angewendet, aber EnsureTokenIsValid wird ausgeschlossen
    #[WithoutMiddleware(EnsureTokenIsValid::class)]
    public function index(): JsonResponse { /* ... */ }
}
```

### Anwendung auf Klassen und `only` / `except`

Wenn Sie `#[WithoutMiddleware]` auf Klassenebene anbringen, wird die Middleware für alle Aktionen, einschließlich abgeleiteter Klassen, ausgeschlossen. Mit `only` / `except` können Sie den Umfang des Ausschlusses einschränken.

```php theme={null}
#[Middleware('auth')]
#[WithoutMiddleware('subscribed', except: ['index'])]
class AdminController
{
    // subscribed wird angewendet (durch except: ['index'] nicht ausgeschlossen)
    public function index(): View { /* ... */ }

    // subscribed wird ausgeschlossen
    public function dashboard(): View { /* ... */ }
    public function settings(): View { /* ... */ }
}
```

<Warning>
  `#[WithoutMiddleware]` wirkt nur für **Route-Middleware**. Globale Middleware, die in `app/Http/Kernel.php` registriert ist, kann nicht ausgeschlossen werden.
</Warning>

## `#[Authorize]` — Autorisierung über Policies

Als Kurzform für die `can`-Middleware können Sie Autorisierungsprüfungen über Policies deklarativ per Attribut definieren.

### Grundlegende Verwendung

```php theme={null}
use App\Models\Post;
use Illuminate\Routing\Attributes\Controllers\Authorize;

class PostController
{
    // Prüft die Fähigkeit 'viewAny' (Methode viewAny in der Post-Policy)
    #[Authorize('viewAny', Post::class)]
    public function index(): View { /* ... */ }

    // Prüft die Fähigkeit 'view' (übergibt den Route-Parameter 'post')
    #[Authorize('view', 'post')]
    public function show(Post $post): View { /* ... */ }

    // Prüft die Fähigkeit 'create'
    #[Authorize('create', Post::class)]
    public function create(): View { /* ... */ }

    #[Authorize('create', Post::class)]
    public function store(Request $request): Response { /* ... */ }

    // Prüft die Fähigkeit 'update' (übergibt den Route-Parameter)
    #[Authorize('update', 'post')]
    public function edit(Post $post): View { /* ... */ }

    #[Authorize('update', 'post')]
    public function update(Request $request, Post $post): Response { /* ... */ }

    #[Authorize('delete', 'post')]
    public function destroy(Post $post): Response { /* ... */ }
}
```

### Argumente der Policy

Als zweites Argument können Sie Folgendes übergeben:

| Wert                       | Beschreibung                                                                          |
| -------------------------- | ------------------------------------------------------------------------------------- |
| `Post::class`              | Modellklasse (wenn keine Modellinstanz nötig ist, z. B. bei `viewAny`)                |
| `'post'`                   | Name eines Route-Parameters (die per Model Binding aufgelöste Instanz wird übergeben) |
| `[Comment::class, 'post']` | Mehrere Argumente (werden der Policy-Methode als Array übergeben)                     |

```php theme={null}
use App\Models\Comment;
use App\Models\Post;
use Illuminate\Routing\Attributes\Controllers\Authorize;

class CommentController
{
    // Übergibt der Policy $post (Route-Parameter) und die Comment-Klasse
    #[Authorize('create', [Comment::class, 'post'])]
    public function store(Post $post, Request $request): Response
    {
        // ...
    }

    #[Authorize('delete', 'comment')]
    public function destroy(Comment $comment): Response
    {
        // ...
    }
}
```

### Vergleich mit der `can`-Middleware

```php theme={null}
// Klassische Schreibweise (Route-Facade)
Route::get('/posts', [PostController::class, 'index'])->middleware('can:viewAny,App\Models\Post');
Route::put('/posts/{post}', [PostController::class, 'update'])->middleware('can:update,post');

// Schreibweise mit Attributen
class PostController
{
    #[Authorize('viewAny', Post::class)]
    public function index(): View { /* ... */ }

    #[Authorize('update', 'post')]
    public function update(Request $request, Post $post): Response { /* ... */ }
}
```

Sie müssen die Middleware nicht mehr in der Route-Datei angeben, und die Autorisierungslogik wird im Controller gebündelt.

## Praxisbeispiele

### Anwendung auf Resource Controller

```php theme={null}
use App\Models\Article;
use Illuminate\Routing\Attributes\Controllers\Authorize;
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class ArticleController
{
    #[Authorize('viewAny', Article::class)]
    public function index(): View
    {
        return view('articles.index', [
            'articles' => Article::paginate(),
        ]);
    }

    #[Authorize('view', 'article')]
    public function show(Article $article): View
    {
        return view('articles.show', compact('article'));
    }

    #[Authorize('create', Article::class)]
    public function create(): View
    {
        return view('articles.create');
    }

    #[Authorize('create', Article::class)]
    public function store(StoreArticleRequest $request): RedirectResponse
    {
        $article = Article::create($request->validated());

        return redirect()->route('articles.show', $article);
    }

    #[Authorize('update', 'article')]
    public function edit(Article $article): View
    {
        return view('articles.edit', compact('article'));
    }

    #[Authorize('update', 'article')]
    public function update(UpdateArticleRequest $request, Article $article): RedirectResponse
    {
        $article->update($request->validated());

        return redirect()->route('articles.show', $article);
    }

    #[Authorize('delete', 'article')]
    public function destroy(Article $article): RedirectResponse
    {
        $article->delete();

        return redirect()->route('articles.index');
    }
}
```

### Anwendung auf API-Controller

```php theme={null}
use Illuminate\Routing\Attributes\Controllers\Middleware;
use Illuminate\Routing\Attributes\Controllers\WithoutMiddleware;

#[Middleware('auth:sanctum')]
#[Middleware('throttle:api')]
class ApiPostController
{
    // Die Auflistung ist ohne Authentifizierung möglich
    #[WithoutMiddleware('auth:sanctum')]
    public function index(): JsonResponse
    {
        return response()->json(Post::paginate());
    }

    public function store(Request $request): JsonResponse
    {
        // Nur für authentifizierte Nutzer
    }
}
```

## Verarbeitungsreihenfolge der Attribute

Wenn mehrere Attribute angebracht sind, ist die Verarbeitungsreihenfolge wie folgt:

```mermaid theme={null}
flowchart LR
    A["Request"] --> B["#[Middleware]<br>auf Klassenebene"]
    B --> C["#[Middleware]<br>auf Methodenebene"]
    C --> D["Ausschlussverarbeitung<br>#[WithoutMiddleware]"]
    D --> E["Autorisierungsprüfung<br>#[Authorize]"]
    E --> F["Ausführung der<br>Controller-Methode"]
```

<Info>
  `#[Authorize]` wird intern wie die `can`-Middleware behandelt und daher in derselben Pipeline verarbeitet wie `#[Middleware]`.
</Info>

## Zusammenfassung: Welche Variante sollten Sie wählen?

| Situation                                         | Empfohlener Ansatz                      |
| ------------------------------------------------- | --------------------------------------- |
| Neuer Controller (Laravel 13)                     | Attribute verwenden                     |
| Bestehender Controller mit `middleware()`-Methode | Schrittweise Migration zu Attributen    |
| Dynamische Middleware-Konfiguration erforderlich  | `middleware()`-Methode weiter verwenden |
| Zentrale Verwaltung in Route-Dateien gewünscht    | `Route::middleware()` weiter verwenden  |

## Nächste Schritte

<Columns cols={2}>
  <Card title="PHP-Attribute (Queue, Eloquent)" icon="code" href="/de/advanced/php-attributes">
    Erläuterung der PHP-Attribute, die in Queue-Jobs und Eloquent-Modellen verwendet werden können.
  </Card>

  <Card title="Fortgeschritten: Controller" icon="layer-group" href="/de/controllers">
    Grundlagen zur Verwendung von Laravel-Controllern.
  </Card>
</Columns>


## Related topics

- [Controller](/de/controllers.md)
- [PHP-Attribute](/de/advanced/php-attributes.md)
- [Übersicht der neuen Features in Laravel 13](/de/blog/laravel-13-new-features.md)
- [Socialite für Discord](/de/packages/socialite-discord.md)
- [Amazon-Bedrock-Treiber für das Laravel AI SDK](/de/packages/laravel-amazon-bedrock.md)
