# Aktivieren von CORS (Cross-Origin Resource Sharing) in Sisk

Source: https://docs.sisk-framework.org/de/docs/features/cors.html

Sisk verfügt über ein Werkzeug, das beim Umgang mit [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) nützlich sein kann, wenn Sie Ihren Dienst öffentlich bereitstellen. Diese Funktion ist kein Teil des HTTP‑Protokolls, sondern ein spezifisches Merkmal von Webbrowsern, definiert vom W3C. Dieser Sicherheitsmechanismus verhindert, dass eine Webseite Anfragen an eine andere Domain stellt als die, von der die Seite bereitgestellt wurde. Ein Dienstanbieter kann bestimmten Domains den Zugriff auf seine Ressourcen erlauben, oder nur einer.

## Gleiche Herkunft

Um eine Ressource als „gleiche Herkunft“ zu identifizieren, muss eine Anfrage den [Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Origin)-Header in ihrer Anfrage angeben:

```http
GET /api/users HTTP/1.1
Host: example.com
Origin: http://example.com
...
```

Und der entfernte Server muss mit einem [Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)-Header antworten, der denselben Wert wie die angeforderte Herkunft enthält:

```http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
...
```

Diese Überprüfung ist **explizit**: Host, Port und Protokoll müssen mit der Anfrage übereinstimmen. Betrachten Sie das Beispiel:

- Ein Server gibt zurück, dass sein `Access-Control-Allow-Origin` `https://example.com` ist:
    - `https://example.net` – die Domain ist unterschiedlich.
    - `http://example.com` – das Schema ist unterschiedlich.
    - `http://example.com:5555` – der Port ist unterschiedlich.
    - `https://www.example.com` – der Host ist unterschiedlich.

In der Spezifikation ist nur die Syntax für beide Header zulässig, sowohl für Anfragen als auch für Antworten. Der URL‑Pfad wird ignoriert. Der Port wird ebenfalls weggelassen, wenn er ein Standardport ist (80 für HTTP und 443 für HTTPS).

```http
Origin: null
Origin: <scheme>://<hostname>
Origin: <scheme>://<hostname>:<port>
```

## CORS aktivieren

Standardmäßig steht Ihnen das Objekt [CrossOriginResourceSharingHeaders](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.md) innerhalb Ihres [ListeningHost](https://docs.sisk-framework.org/api/Sisk.Core.Http.ListeningHost.md) zur Verfügung.

Sie können CORS beim Initialisieren des Servers konfigurieren:

```csharp
static async Task Main(string[] args)
{
    using var app = HttpServer.CreateBuilder()
        .UseCors(new CrossOriginResourceSharingHeaders(
            allowOrigin: "http://example.com",
            allowHeaders: ["Authorization"],
            exposeHeaders: ["Content-Type"]))
        .Build();

    await app.StartAsync();
}
```

Der obige Code sendet die folgenden Header für **alle Antworten**:

```http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Headers: Authorization
Access-Control-Expose-Headers: Content-Type
```

Diese Header müssen für alle Antworten an einen Web‑Client gesendet werden, einschließlich Fehlermeldungen und Weiterleitungen.

Sie werden feststellen, dass die Klasse [CrossOriginResourceSharingHeaders](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.md) zwei ähnliche Eigenschaften besitzt: [AllowOrigin](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.AllowOrigin.md) und [AllowOrigins](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.AllowOrigins.md). Beachten Sie, dass die eine im Plural, die andere im Singular steht.

- Die **AllowOrigin**‑Eigenschaft ist statisch: Nur die von Ihnen angegebene Herkunft wird für alle Antworten gesendet.
- Die **AllowOrigins**‑Eigenschaft ist dynamisch: Der Server prüft, ob die Herkunft der Anfrage in dieser Liste enthalten ist. Wird sie gefunden, wird sie für die Antwort dieser Herkunft gesendet.

Wenn die erlaubte Herkunft von der Anfrage abhängt, also wenn Sie **AllowOrigins** oder den unten beschriebenen [AutoAllowOrigin](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.AutoAllowOrigin.md)-Wert verwenden, sendet Sisk zusätzlich den Header `Vary: Origin`, damit Caches keine Antwort für eine andere Herkunft wiederverwenden.

### Platzhalter und automatische Header

Alternativ können Sie ein Platzhalterzeichen (`*`) in der Herkunft der Antwort verwenden, um anzugeben, dass jede Herkunft Zugriff auf die Ressource hat. Dieser Wert ist jedoch für Anfragen mit Anmeldeinformationen (Autorisation‑Header) nicht zulässig und diese Operation [führt zu einem Fehler](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS/Errors/CORSNotSupportingCredentials).

Sie können dieses Problem umgehen, indem Sie explizit auflisten, welche Herkünfte über die [AllowOrigins](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.AllowOrigins.md)‑Eigenschaft erlaubt werden, oder indem Sie die Konstante [AutoAllowOrigin](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.AutoAllowOrigin.md) im Wert von [AllowOrigin](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.AllowOrigin.md) verwenden. Diese magische Eigenschaft definiert den `Access-Control-Allow-Origin`‑Header mit demselben Wert wie der `Origin`‑Header der Anfrage.

Sie können außerdem [AutoFromRequestMethod](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.AutoFromRequestMethod.md) und [AutoFromRequestHeaders](https://docs.sisk-framework.org/api/Sisk.Core.Entity.CrossOriginResourceSharingHeaders.AutoFromRequestHeaders.md) für ein Verhalten ähnlich wie `AllowOrigin` verwenden, das automatisch basierend auf den gesendeten Headern antwortet.

```csharp
using var host = HttpServer.CreateBuilder()
    .UseCors(new CrossOriginResourceSharingHeaders(
        
        // Antwortet basierend auf dem Origin-Header der Anfrage
        allowOrigin: CrossOriginResourceSharingHeaders.AutoAllowOrigin,
        
        // Antwortet basierend auf dem Access-Control-Request-Method-Header oder der Anfragemethode
        allowMethods: [CrossOriginResourceSharingHeaders.AutoFromRequestMethod],

        // Antwortet basierend auf dem Access-Control-Request-Headers-Header oder den gesendeten Headern
        allowHeaders: [CrossOriginResourceSharingHeaders.AutoFromRequestHeaders],

        exposeHeaders: [HttpKnownHeaderNames.ContentType, "X-Authenticated-Account-Id"],
        allowCredentials: true))
    .Build();
```

## Weitere Möglichkeiten, CORS anzuwenden

Wenn Sie mit [service providers](https://docs.sisk-framework.org/de/docs/extensions/service-providers.md) arbeiten, können Sie Werte, die in der Konfigurationsdatei definiert sind, überschreiben:

```csharp
static async Task Main(string[] args)
{
    using var app = HttpServer.CreateBuilder()
        .UsePortableConfiguration(...)
        .UseCors(cors => {
            // Überschreibt den in der Konfiguration definierten Ursprung
            // Datei.
            cors.AllowOrigin = "http://example.com";
        })
        .Build();

    await app.StartAsync();
}
```

## Deaktivieren von CORS für bestimmte Routen

```csharp
[RoutePrefix("api/widgets")]
public class WidgetController : Controller {

    // GET /api/widgets/colors
    [RouteGet("/colors", UseCors = false)]
    public IEnumerable<string> GetWidgets() {
        return new[] { "Green widget", "Red widget" };
    }
}
```

## Werte in der Antwort ersetzen

Sie können Werte in einer Router‑Aktion explizit ersetzen oder entfernen:

```csharp
[RoutePrefix("api/widgets")]
public class WidgetController : Controller {

    public IEnumerable<string> GetWidgets(HttpRequest request) {

        // Entfernt den Access-Control-Allow-Credentials-Header
        request.Context.OverrideHeaders.AccessControlAllowCredentials = string.Empty;
        
        // Ersetzt den Access-Control-Allow-Origin-Header
        request.Context.OverrideHeaders.AccessControlAllowOrigin = "https://contorso.com";

        return new[] { "Green widget", "Red widget" };
    }
}
```

## Preflight-Anfragen

Eine Preflight‑Anfrage ist eine [OPTIONS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods/OPTIONS)-Methoden‑Anfrage, die der Client vor der eigentlichen Anfrage sendet.

Wenn eine Anfrage mit der Methode `OPTIONS` dem Pfad einer Route entspricht, aber keine Route explizit für `OPTIONS` konfiguriert ist, antwortet der Sisk‑Server mit einem `200 OK` und den zutreffenden CORS‑Headern, woraufhin der Client mit der eigentlichen Anfrage fortfahren kann.

- Wenn eine Route explizit mit [RouteMethod.Options](https://docs.sisk-framework.org/api/Sisk.Core.Routing.RouteMethod.md) gemappt ist, zum Beispiel mit `MapOptions`, verarbeitet diese Route die Anfrage anstelle der automatischen Antwort.
- Wenn die Route, die dem Pfad entspricht, `UseCors = false` hat, wird die automatische Antwort weiterhin gesendet, jedoch ohne CORS‑Header.

> [!NOTE]
> Vor Sisk 1.7 enthielt die automatische Preflight‑Antwort stets die CORS‑Header, selbst für Routen mit `UseCors = false`.

## CORS global deaktivieren

Dies ist nicht möglich. Um CORS nicht zu verwenden, konfigurieren Sie es einfach nicht.
