guideASP.NET Core

本指南介绍了与 ASP.NET Core 应用程序的集成。如果您想直接跳转到代码,可以在 GitHub 上找到本指南中描述的应用程序的完整代码

# 先决条件

在开始之前,请确保您的系统中已安装 .NET SDK 7.0。如果命令行中无法使用 dotnet 工具,请先访问 .NET SDK 下载页面

# 创建应用程序

作为示例的基础,我们将创建一个新的项目目录和一个使用以下命令创建的空 ASP.NET 项目

dotnet new web --name AspdotnetCkbox

项目创建后,您可以启动开发服务器

cd AspdotnetCkbox
dotnet run

该应用程序将在控制台中列出的端口下可用,例如 https://127.0.0.1:5063。您也可以在 Properties/launchSettings.json 文件中调整端口。

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "https://127.0.0.1:52536",
      "sslPort": 44341
    }
  },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://127.0.0.1:5063",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://127.0.0.1:7029;https://127.0.0.1:5063",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

# 创建令牌端点

CKBox 与其他 CKEditor 云服务一样,使用 JWT 令牌进行身份验证和授权。有关如何创建访问凭据的信息,请参阅 身份验证 指南中的 创建访问凭据 部分。

现在我们有了所需的访问凭据,即:环境 ID 和访问密钥,让我们创建令牌端点。

首先,让我们安装 System.IdentityModel.Tokens.Jwt 包,用于创建 JWT 令牌。

dotnet add package System.IdentityModel.Tokens.Jwt

# 完整端点代码

// Program.cs
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using Microsoft.IdentityModel.Tokens;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/token", () =>
{

    var environmentId = builder.Configuration.GetValue<string>("CKBoxEnvironmentId");
    var accessKey = builder.Configuration.GetValue<string>("CKBoxAccessKey");
    var securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(accessKey));

    var signingCredentials = new SigningCredentials(securityKey, "HS256");
    var header = new JwtHeader(signingCredentials);

    var dateTimeOffset = new DateTimeOffset(DateTime.UtcNow);

    var payload = new JwtPayload
    {
        { "aud", environmentId },
        { "iat", dateTimeOffset.ToUnixTimeSeconds() },
        { "sub", "user-123" },
        { "user", new Dictionary<string, string> {
            { "email", "joe.doe@example.com" },
            { "name", "Joe Doe" }
        } },
        { "auth", new Dictionary<string, object> {
            { "ckbox", new Dictionary<string, string> {
                { "role", "admin" }
            } }
        } }
    };

    var securityToken = new JwtSecurityToken(header, payload);
    var handler = new JwtSecurityTokenHandler();

    return handler.WriteToken(securityToken);
});

app.Run();

正如您在上面的代码清单中所看到的,签署 JWT 令牌所需的访问凭据是从 Configuration 对象中获取的。借助此功能,您可以方便地将它们添加到 appsettings.json 文件中

{
  "CKBoxAccessKey": "REPLACE-WITH-ACCESS-KEY",
  "CKBoxEnvironmentId": "REPLACE-WITH-ENVIRONMENT-ID",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

# 将 CKBox 脚本添加到页面

CKBox 可以通过多种方式嵌入到应用程序中。为简单起见,在本例中,我们将使用从 CDN 提供的 CKBox 脚本。

本指南中的示例将涵盖使用 CKBox 的三种常见场景

  • CKBox 与 CKEditor 5 集成。
  • CKBox 用作对话框模式下的文件选择器。
  • CKBox 用作全页面应用程序。

首先,让我们向我们的应用程序添加 Razor 模板支持。

// Program.cs
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using Microsoft.IdentityModel.Tokens;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();

app.MapGet("/token", () =>
{

    var environmentId = builder.Configuration.GetValue<string>("CKBoxEnvironmentId");
    var accessKey = builder.Configuration.GetValue<string>("CKBoxAccessKey");
    var securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(accessKey));

    var signingCredentials = new SigningCredentials(securityKey, "HS256");
    var header = new JwtHeader(signingCredentials);

    var dateTimeOffset = new DateTimeOffset(DateTime.UtcNow);

    var payload = new JwtPayload
    {
        { "aud", environmentId },
        { "iat", dateTimeOffset.ToUnixTimeSeconds() },
        { "sub", "user-123" },
        { "user", new Dictionary<string, string> {
            { "email", "joe.doe@example.com" },
            { "name", "Joe Doe" }
        } },
        { "auth", new Dictionary<string, object> {
            { "ckbox", new Dictionary<string, string> {
                { "role", "admin" }
            } }
        } }
    };

    var securityToken = new JwtSecurityToken(header, payload);
    var handler = new JwtSecurityTokenHandler();

    return handler.WriteToken(securityToken);
});

app.MapRazorPages();
app.Run();

为了避免代码重复,让我们准备一个包含 CKBox 脚本的基本布局,我们将在所有三个示例中重复使用该布局

Pages/Shared/_Layout.cshtml

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>CKBox example</title>
    <script src="https://cdn.ckbox.io/ckbox/2.5.1/ckbox.js"></script>
    @await RenderSectionAsync("Head", required: false)
</head>
<body>

@RenderBody()

</body>
</html>

现在,让我们添加三个示例的页面。

# CKBox 与 CKEditor 5

在本例中,我们将使用最快速简便的方式运行 CKEditor 5 - 从 CDN 提供。有关更高级的集成方案,请参阅 CKEditor 5 文档

让我们创建扩展我们在上一步中创建的布局的子视图

Pages/index.cshtml

@page

@{
    Layout = "Shared/_Layout";
    var tokenUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}/token";
}

@section Head {
    <script type="importmap">
        {
            "imports": {
                "ckeditor5": "https://cdn.ckeditor.com/ckeditor5/42.0.0/ckeditor5.js",
                "ckeditor5/": "https://cdn.ckeditor.com/ckeditor5/42.0.0/"
            }
        }
    </script>
    <link rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5/42.0.0/ckeditor5.css" />
}
<div>
    <textarea id="editor">@Html.Raw("Hello world")</textarea>

    <script type="module">
        import {
            ClassicEditor,
            CKBox,
            Essentials,
            Bold,
            Italic,
            Font,
            Paragraph
        } from 'ckeditor5';

        ClassicEditor
            .create( document.querySelector( '#editor' ), {
                plugins: [ CKBox, Essentials, Bold, Italic, Font, Paragraph ],
                ckbox: {
                    tokenUrl: 'https://your.token.url',
                    theme: 'lark'
                },
                toolbar: [
                    'ckbox', '|', 'undo', 'redo', '|', 'bold', 'italic', '|',
                    'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor'
                ],
            } )
            .catch( error => {
                console.error( error );
            } );
    </script>
</div>

上面的示例包含从 CDN 提供的 预定义的 CKEditor 5 构建,其中包含所需的 CKBox 插件。然后,通过设置 ckbox 属性的必需参数,将 CKEditor 5 配置为使用 CKBox。请注意,在 ckbox.tokenUrl 配置选项中,我们传递了之前步骤中创建的令牌端点的 URL,该 URL 将用于获取用于在 CKBox 中验证用户的 JWT 令牌。

# CKBox 作为文件选择器

常见场景之一是将 CKBox 用作文件选择器,用户可以在其中选择文件管理器中存储的文件之一。选择文件后,我们希望获取有关所选文件的信息,尤其是它们的 URL。这可以通过使用作为 CKBox 配置选项传递的 assets.onChoose 回调来实现

Pages/filePicker.cshtml

@page

@{
    Layout = "Shared/_Layout";
    var tokenUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}/token";
}

<div>
    <input type="text" id="file-url"></input><button id="choose">Choose file</button>
        <div id="ckbox"></div>
        <script>
            document.getElementById('choose').addEventListener('click', function () {
                CKBox.mount(document.querySelector('#ckbox'), {
                    tokenUrl: '@tokenUrl',
                    dialog: true,
                    assets: {
                        // Callback executed after choosing assets
                        onChoose: (assets) => {
                            document.getElementById('file-url').value = assets[0].data.url;
                            assets.forEach((asset) => {
                                console.log(asset.data.url);
                            })
                        }
                    }
                });
            });
        </script>
</div>

该示例将在 https://127.0.0.1:5063/filePicker 下可用。

# CKBox 在全页面模式下

要以全页面模式启动 CKBox,您可以将其附加到 document.body 并调整所需的 CSS 样式

Pages/fullPage.cshtml

@page

@{
    Layout = "Shared/_Layout";
    var tokenUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}/token";
}

@section Head {
    <style>
            html, body {
                margin: 0;
                padding: 0;
                height: 100vh;
            }
    </style>
}

<div>
    <script>
        CKBox.mount(document.body, {
            tokenUrl: '@tokenUrl',
        });
    </script>
</div>

该示例将在 https://127.0.0.1:5063/fullPage 下可用。

# 完整代码

您可以在 GitHub 上找到本指南中描述的应用程序的完整代码