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

# BuildingBlocks.FileServer

> Statik dosya sunumu — auth-aware özel file provider, dizin listeleme ve query-param token ile koruma.

`BuildingBlocks.FileServer`, fiziksel disk üzerindeki dosyaları HTTP üzerinden sunar. İki çalışma modu vardır: korumasız `PhysicalFileProvider` veya kimlik kontrolü yapan `PrivateMaviDepoFileProvider`. İkinci modda her dosya/dizin erişiminden önce `IFileServerUserContext.IsAuthenticated()` çağrılır; yetkisiz istek `404` (var olmuyormuş gibi) döner.

## DI ve middleware

| Metot                                  | Tip                   | Amaç                                                                          |
| -------------------------------------- | --------------------- | ----------------------------------------------------------------------------- |
| `AddMaviDepoFileServer(configuration)` | `IServiceCollection`  | `FileProviderOptions`'ı `FileProvider` bölümüne bind eder                     |
| `UseMaviDepoFileServer(configuration)` | `IApplicationBuilder` | Provider'ı seçer ve `UseFileServer` (+ opsiyonel `UseDirectoryBrowser`) kurar |

```csharp theme={null}
public static IApplicationBuilder UseMaviDepoFileServer(this IApplicationBuilder app, IConfiguration configuration)
{
    string root = configuration["FileProvider:Root"];
    var requestPath = new PathString(configuration["FileProvider:RequestPath"]);
    bool enableDirectoryBrowsing = Convert.ToBoolean(configuration["FileProvider:EnableDirectoryBrowsing"]);
    bool enableAuth = Convert.ToBoolean(configuration["FileProvider:EnableAuth"]);

    IFileProvider provider = enableAuth
        ? new PrivateMaviDepoFileProvider(app.ApplicationServices, root)  // auth-aware
        : new PhysicalFileProvider(root);                                 // public

    app.UseFileServer(new FileServerOptions
    {
        FileProvider = provider,
        RequestPath = requestPath,
        EnableDirectoryBrowsing = enableDirectoryBrowsing
    });
    return app;
}
```

## Konfigürasyon — `FileProviderOptions`

`FileProvider` bölümüne bind edilir.

| Üye                            | Tip      | Açıklama                                                                 |
| ------------------------------ | -------- | ------------------------------------------------------------------------ |
| `Root`                         | `string` | Sunulacak dosyaların kök dizini (ör. `/var/files`, `C:\files`)           |
| `RequestPath`                  | `string` | URL ön eki — `/files`                                                    |
| `EnableDirectoryBrowsing`      | `bool`   | Dizin listeleme (sıralı HTML formatter ile)                              |
| `EnableAuth` (config anahtarı) | `bool`   | `true` → `PrivateMaviDepoFileProvider`, `false` → `PhysicalFileProvider` |

```json theme={null}
{
  "FileProvider": {
    "Root": "/var/files",
    "RequestPath": "/files",
    "EnableDirectoryBrowsing": false,
    "EnableAuth": true
  }
}
```

<Note>
  `UseMaviDepoFileServer`, auth seçimini config'ten okunan `FileProvider:EnableAuth` anahtarıyla yapar. POCO sınıfında bu alan tarihsel olarak `EnableAuthorization` adını taşır; etkin olan değer middleware'in okuduğu `FileProvider:EnableAuth` anahtarıdır.
</Note>

## `PrivateMaviDepoFileProvider` — auth-aware sunum

`PhysicalFileProvider`'ı genişletir. `GetFileInfo`/`GetDirectoryContents` çağrılarında bir scope açıp `IFileServerUserContext` çözer:

```csharp theme={null}
public new IFileInfo GetFileInfo(string subpath)
{
    using IServiceScope scope = _serviceProvider.CreateScope();
    var user = scope.ServiceProvider.GetRequiredService<IFileServerUserContext>();

    if (!user.IsAuthenticated())
        return new NotFoundFileInfo(subpath);   // yetkisiz → "yok" gibi davran

    return base.GetFileInfo(subpath);
}
```

`IFileServerUserContext` uygulama tarafından implement edilir: `KullaniciId`, `TenantId`, `Eposta`, `Token`, `IsAuthenticated()`.

## Keycloak query-param token

`<img src>` / `<a href>` gibi tarayıcı kaynaklı isteklere `Authorization` header eklenemez. Bu yüzden Keycloak JWT şeması `/files` (ve `/hubs`) yolları için token'ı **query string'den** okuyacak şekilde yapılandırılmıştır:

```csharp theme={null}
// BuildingBlocks.Keycloak — JwtBearerEvents.OnMessageReceived
var accessToken = ctx.Request.Query["access_token"];
if (!string.IsNullOrEmpty(accessToken) &&
    ctx.HttpContext.Request.Path.StartsWithSegments("/files"))
{
    ctx.Token = accessToken;
}
```

Böylece frontend dosyayı şu şekilde isteyebilir:

```text theme={null}
GET /files/raporlar/2026/ozet.pdf?access_token=eyJhbGciOiJSUzI1Ni␣...
```

<Warning>
  Query-param token URL'de görünür (proxy/log'lara düşebilir). Yalnızca kısa ömürlü access token ile, HTTPS arkasında ve `/files` gibi sınırlı yollar için kullanın. `EnableDirectoryBrowsing`'i prod'da kapalı tutun.
</Warning>

## Kullanım

```csharp theme={null}
// Program.cs
builder.Services.AddMaviDepoFileServer(builder.Configuration);

var app = builder.Build();
app.UseAuthentication();   // token'ın çözülmesi için ÖNCE
app.UseAuthorization();
app.UseMaviDepoFileServer(builder.Configuration);
```

## İlgili

<CardGroup cols={2}>
  <Card title="Keycloak" icon="key" href="/building-blocks/keycloak">
    JWT şeması ve query-param token okuma.
  </Card>

  <Card title="Kimlik doğrulama" icon="fingerprint" href="/security/authentication">
    Şema seçimi ve yetkilendirme.
  </Card>

  <Card title="Docker (prod)" icon="docker" href="/operations/docker-prod">
    nginx-proxy arkasında dosya yolları.
  </Card>

  <Card title="API" icon="server" href="/api/overview">
    Statik içerik ve controller pipeline'ı.
  </Card>
</CardGroup>
