---
title: "sdk/dotnet"
description: ".NET 8 服务端 SDK，提供 networkless JWT 验证、ASP.NET Core 请求认证和 webhook 签名校验。"
locale: "zh-Hans"
---

> Documentation Index
> Fetch the relevant documentation index at: https://vonvon.id/zh-hans/sdks/llms.txt
> Use this file to discover all available pages before exploring further.

# sdk/dotnet

## 状态

已在本地实现并验证。针对真实 Vonvon 实例的 IdP 往返验证（JWKS 获取、token 签名/验证）尚未执行，生产使用前必须完成。

Registry 状态:UNPUBLISHED。此 SDK 只能从仓库源码 checkout 安装；不要使用外部 package registry。

请求认证默认仅接受 Bearer。只有配置精确名称时才读取应用自有 JWT cookie。SDK 绝不扫描或本地验证 opaque \_\_Host-vonvon.rt.\* Core cookie；应将完整 Cookie header 转发到 exact same-origin POST /v1/sessions/token，并禁用 redirect，且只接受仅包含 token 字段的响应。

## 安装

需要 .NET 8 目标框架。

```xml
<ItemGroup>
  <ProjectReference Include="../vonvon/sdk/dotnet/Vonvon.csproj" />
</ItemGroup>
```

## ASP.NET Core 配置（推荐）

```csharp
// Program.cs
using Vonvon;

builder.Services.AddVonvon(options =>
{
options.Issuer   = "https://vonvon.id";
options.Audience = "your-client-id"; // optional
});
```

## 认证请求

```csharp
// Controller / Minimal API
public class MyController(VonvonClient vonvon) : ControllerBase
{
[HttpGet("/me")]
public async Task<IActionResult> GetMe()
{
    var auth = await vonvon.AuthenticateRequestAsync(
        authorizationHeader: Request.Headers.Authorization);

    if (!auth.Authenticated)
        return Unauthorized(auth.Reason);

    return Ok(new { sub = auth.Claims!.Sub, email = auth.Claims.Email });
}

private Task<string> ExchangeSessionAsync() => vonvon.ExchangeSessionTokenAsync(
    $"{Request.Scheme}://{Request.Host}{Request.Path}",
    Request.Headers.Cookie.ToString());
}
```

## 直接验证 token

```csharp
using Vonvon;

var client = new VonvonClient(new VonvonOptions { Issuer = "https://vonvon.id" });

try
{
var claims = await client.VerifyTokenAsync("eyJ...");
Console.WriteLine($"sub={claims.Sub} email={claims.Email}");
}
catch (TokenVerificationException ex)
{
Console.WriteLine($"Invalid token: {ex.Message}");
}
```

## 验证 webhook

```csharp
app.MapPost("/webhooks/vonvon", async (HttpRequest req, VonvonClient vonvon) =>
{
using var ms = new MemoryStream();
await req.Body.CopyToAsync(ms);
var body = ms.ToArray();

var headers = new Dictionary<string, string>
{
    ["svix-id"]        = req.Headers["svix-id"].ToString(),
    ["svix-timestamp"] = req.Headers["svix-timestamp"].ToString(),
    ["svix-signature"] = req.Headers["svix-signature"].ToString(),
};

var webhookSecret = Environment.GetEnvironmentVariable("VONVON_WEBHOOK_SECRET")
    ?? throw new InvalidOperationException("VONVON_WEBHOOK_SECRET is required");

try
{
    var webhook = vonvon.VerifyWebhook(body, headers, secret: webhookSecret);
    return Results.Ok();
}
catch (WebhookVerificationException ex)
{
    return Results.BadRequest(ex.Message);
}
});
```

## VonvonOptions

| 属性 | 默认 | 描述 |
| --- | --- | --- |
| `Issuer` | 必填 | Vonvon 签发方 URL |
| `Audience` | `null` | 期望的 aud claim；null 跳过验证 |
| `JwksTtl` | 1 小时 | JWKS 内存缓存 TTL |
| `SessionCookieName` | `disabled` | 应用自有 JWT cookie 名；仅在显式配置后启用 |
| `ClockSkew` | 5 分钟 | JWT exp/nbf 时钟偏差容忍度 |
| `WebhookToleranceWindow` | 5 分钟 | Webhook 重放防护窗口 |

## VonvonClient API

| 方式 | 描述 |
| --- | --- |
| `VerifyTokenAsync(token, ct)` | 验证 JWT 字符串；失败时抛出 `TokenVerificationException`。 |
| `AuthenticateRequestAsync(authHeader, cookies, ct)` | 提取并验证 token；返回 `AuthStatus`；不抛出异常。 |
| `VerifyWebhook(payload, headers, secret)` | 校验 webhook 签名；失败时抛出 `WebhookVerificationException`。同步执行。 |

## 平台注意事项

- 使用 `Microsoft.IdentityModel.Tokens` 和 `System.IdentityModel.Tokens.Jwt` 8.x。ES256 为主要算法；支持 RS256 和 PS256。
- `AddVonvon()` 将 `VonvonClient` 注册为单例，并接入 `IHttpClientFactory` 用于 JWKS 获取。
- 异常层级：`VonvonException` -&gt; `JwksException`、`TokenVerificationException`、`WebhookVerificationException`。

Source: https://vonvon.id/zh-hans/sdks/dotnet/index.mdx
