Sisk

在 Sisk 中启用 CORS(跨域资源共享)

本页由英文自动翻译。 阅读原文

Sisk 提供了一个工具,可在公开服务时处理跨域资源共享 (CORS)。该功能并非 HTTP 协议的一部分,而是由 W3C 定义的浏览器特性。此安全机制阻止网页向提供该网页的域之外的域发起请求。服务提供者可以允许特定域或单个域访问其资源。

Same Origin #

要将资源标识为“同源”,请求必须在其请求中包含 Origin 头部:

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

远程服务器必须在响应中返回一个与请求的 Origin 值相同的 Access-Control-Allow-Origin 头部:

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

此验证是显式的:主机、端口和协议必须与请求的完全一致。请查看下面的示例:

  • 服务器返回其 Access-Control-Allow-Origin 为 https://example.com:
    • https://example.net - 域名不同。
    • http://example.com - 协议不同。
    • http://example.com:5555 - 端口不同。
    • https://www.example.com - 主机不同。

在规范中,两种头部仅允许使用语法形式,无论是请求还是响应。URL 路径会被忽略。默认端口(HTTP 为 80,HTTPS 为 443)也会被省略。

HTTP
Origin: null
Origin: <scheme>://<hostname>
Origin: <scheme>://<hostname>:<port>

Enabling CORS #

在原生环境中,你可以在 ListeningHost 中使用 CrossOriginResourceSharingHeaders 对象。

可以在初始化服务器时配置 CORS:

C#
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();
}

上述代码会为所有响应发送以下头部:

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

这些头部必须在对 Web 客户端的所有响应中发送,包括错误和重定向。

你可能注意到 CrossOriginResourceSharingHeaders 类有两个相似的属性: AllowOrigin 和 AllowOrigins。请注意,一个是复数形式,另一个是单数形式。

  • AllowOrigin 属性是静态的:仅会发送你指定的单一来源,适用于所有响应。
  • AllowOrigins 属性是动态的:服务器会检查请求的来源是否在此列表中。如果匹配,则在该来源的响应中发送对应的头部。

当允许的来源取决于请求时(即使用 AllowOrigins 或下面描述的 AutoAllowOrigin 值),Sisk 还会发送 Vary: Origin 头部,以防缓存将响应复用于不同的来源。

Wildcards and automatic headers #

或者,你可以在响应的来源中使用通配符 (*) 来表示允许任何来源访问资源。但该值不适用于带有凭证(授权头部)的请求,此操作会导致错误。

可以通过显式列出允许的来源(使用 AllowOrigins 属性),或在 AllowOrigin 的值中使用 AutoAllowOrigin 常量来规避此问题。该魔法属性会将 Access-Control-Allow-Origin 头部设置为请求的 Origin 头部的相同值。

你还可以使用 AutoFromRequestMethod 和 AutoFromRequestHeaders 实现类似 AllowOrigin 的行为,自动根据发送的头部作出响应。

C#
using var host = HttpServer.CreateBuilder()
    .UseCors(new CrossOriginResourceSharingHeaders(
        
        // 根据请求的 Origin 头部作出响应
        allowOrigin: CrossOriginResourceSharingHeaders.AutoAllowOrigin,
        
        // 根据 Access-Control-Request-Method 头部或请求方法作出响应
        allowMethods: [CrossOriginResourceSharingHeaders.AutoFromRequestMethod],

        // 根据 Access-Control-Request-Headers 头部或发送的头部作出响应
        allowHeaders: [CrossOriginResourceSharingHeaders.AutoFromRequestHeaders],

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

Other Ways to Apply CORS #

如果你在使用服务提供者,可以覆盖配置文件中定义的值:

C#
static async Task Main(string[] args)
{
    using var app = HttpServer.CreateBuilder()
        .UsePortableConfiguration(...)
        .UseCors(cors => {
            // 将覆盖配置文件中定义的来源
            // 文件。
            cors.AllowOrigin = "http://example.com";
        })
        .Build();

    await app.StartAsync();
}

Disabling CORS on Specific Routes #

UseCors 属性可用于路由及所有路由属性,并可通过以下示例禁用:

C#
[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" };
    }
}

Replacing Values in the Response #

可以在路由操作中显式替换或移除头部值:

C#
[RoutePrefix("api/widgets")]
public class WidgetController : Controller {

    public IEnumerable<string> GetWidgets(HttpRequest request) {

        // 移除 Access-Control-Allow-Credentials 头部
        request.Context.OverrideHeaders.AccessControlAllowCredentials = string.Empty;
        
        // 替换 Access-Control-Allow-Origin
        request.Context.OverrideHeaders.AccessControlAllowOrigin = "https://contorso.com";

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

Preflight Requests #

预检请求是客户端在实际请求之前发送的OPTIONS 方法请求。

当 OPTIONS 方法的请求匹配某条路由的路径,但该路径没有显式配置 OPTIONS 路由时,Sisk 服务器会返回 200 OK 并附带相应的 CORS 头部,随后客户端即可继续发送实际请求。

  • 如果路由使用 RouteMethod.Options 显式映射,例如使用 MapOptions,则该路由处理请求,而不是自动响应。
  • 如果匹配路径的路由设置了 UseCors = false,仍会发送自动响应,但不包含 CORS 头部。

注意

在 Sisk 1.7 之前,自动预检响应始终携带 CORS 头部,即使路由设置了 UseCors = false。

Disabling CORS Globally #

这在技术上不可行。若不想使用 CORS,只需不要进行配置。

输入关键词以搜索文档和 API 参考。