第七章 在 REST 服务中支持 CORS

第七章 在 REST 服务中支持 CORS

概述

本节提供 CORS 的概述以及如何在 IRIS REST 服务中启用 CORS 的概述。

CORS 简介

跨域资源共享 (CORS) 允许在另一个域中运行的脚本访问服务。

通常,当浏览器从一个域运行脚本时,它允许对同一个域进行 XMLHttpRequest 调用,但在对另一个域进行调用时不允许它们。此浏览器行为限制某人创建可滥用机密数据的恶意脚本。恶意脚本可能允许用户使用授予用户的权限访问另一个域中的信息,但随后在用户不知道的情况下,将机密信息用于其他用途。为了避免这种安全问题,浏览器一般不允许这种跨域调用。

在不使用跨域资源共享 (CORS) 的情况下,具有访问 REST 服务的脚本的网页通常必须与提供 REST 服务的服务器位于同一域中。在某些环境中,将带有脚本的网页与提供 REST 服务的服务器放在不同的域中是很有用的。 CORS 支持这种安排。

下面提供了浏览器如何使用 CORS 处理 XMLHttpRequest 的简化描述:

  1. DomOne 中的网页中的脚本包含对 DomTwo 域中的IRIS REST 服务的 XMLHttpRequestXMLHttpRequest 具有 CORS 的自定义标头。
  2. 用户查看此网页并运行脚本。用户的浏览器检测到与包含网页的域不同的域的 XMLHttpRequest
  3. 用户的浏览器向 IRIS REST 服务发送一个特殊请求,该请求指示 XMLHttpRequestHTTP 请求方法和原始网页的域,在本示例中为 DomOne
  4. 如果请求被允许,则响应包含请求的信息。否则,响应仅包含指示 CORS 不允许请求的标头。

启用 REST 服务以支持 CORS 的概述

默认情况下,REST 服务不允许 CORS 标头。但是,可以启用 CORS 支持。在 REST 服务中启用对 CORS 的支持有两个部分:

  • 启用 REST 服务以接受部分或所有 HTTP 请求的 CORS 标头。。
  • 编写代码,使 REST 服务检查 CORS 请求并决定是否继续。例如,可以提供一个允许列表,其中包含仅包含受信任脚本的域。 IRIS 为文档目的提供了一个简单的默认实现;此默认实现允许任何 CORS 请求。

重要提示:默认 CORS 标头处理不适用于处理机密数据的 REST 服务。

接受 CORS 标头

要指定 REST 服务接受 CORS 标头:

  1. 修改规范类以包含 HandleCorsRequest 参数。

要为所有调用启用 CORS 标头处理,请将 HandleCorsRequest 参数指定为 1

Parameter HandleCorsRequest = 1;

或者,要为某些调用启用 CORS 标头处理,但不是调用,请将 HandleCorsRequest 参数指定为“”(空字符串):

Parameter HandleCorsRequest = "";
  1. 如果将 HandleCorsRequest 参数指定为“”,请编辑规范类中的 OpenAPI XData 块以指示哪些调用支持 CORS。具体来说,对于操作对象,添加以下属性名称和值:
"x-ISC_CORS":true

例如,OpenAPI XData 块可能包含以下内容:

      "post":{
        "description":"Creates a new pet in the store.  Duplicates are allowed",
        "operationId":"addPet",
        "produces":[
          "application/json"
        ],
        ...

添加 x-ISC_CORS 属性,如下所示:

      "post":{
        "description":"Creates a new pet in the store.  Duplicates are allowed",
        "operationId":"addPet",
        "x-ISC_CORS":true, 
        "produces":[
          "application/json"
        ],
        ...
  1. 编译规范类。此操作重新生成调度类,导致行为的实际变化。没有必要详细了解 dispatch 类,但请注意以下变化:
  • 它现在包含 HandleCorsRequest 参数的值。
  • URLMap XData 块现在包含对应于修改的操作的 <Route> 元素的Cors="true"

如果 HandleCorsRequest 参数为 0(默认值),则对所有调用禁用 CORS 标头处理。在这种情况下,如果 REST 服务接收到带有 CORS 标头的请求,则服务会拒绝该请求。

重要提示:IRIS REST 服务支持 OPTIONS 请求(CORS 预检请求),该请求用于确定 REST 服务是否支持 CORS。此请求始终未经身份验证发送,并由 CSPSystem 用户执行。此用户应具有 REST 服务使用的任何数据库的 READ 权限;如果没有,服务将响应 HTTP 404 错误。

定义如何处理 CORS 标头

当启用 REST 服务以接受 CORS 标头时,默认情况下,该服务接受任何 CORS 请求。 REST 服务应检查 CORS 请求并决定是否继续。例如,可以提供一个允许列表,其中包含仅包含受信任脚本的域。为此,需要:

  • 创建 %CSP.REST 的子类。在这个类中,实现第一小节中描述的 OnHandleCorsRequest() 方法。
  • 修改规范类并重新编译,重新生成调度类。

最终结果是调度类从自定义类而不是从 %CSP.REST 继承,因此使用对 OnHandleCorsRequest() 的定义,它覆盖了默认的 CORS 标头处理。

定义 OnHandleCorsRequest()

%CSP.REST 的子类中,定义 OnHandleCorsRequest() 方法,该方法需要检查 CORS 请求并适当地设置响应标头。

要定义此方法,必须熟悉 CORS 协议的细节(此处不讨论)。

还需要知道如何检查请求并设置响应标头。为此,检查默认使用的方法是有用的,即 %CSP.RESTHandleDefaultCorsRequest() 方法。本节说明此方法如何处理源、凭据、标头和请求方法并提出变体建议。可以使用此信息来编写 OnHandleCorsRequest() 方法。

以下代码获取源并使用它来设置响应标头。一种可能的变体是根据允许列表测试来源。然后域被允许,设置响应头。如果不是,请将响应标头设置为空字符串。

    #; Get the origin
    Set tOrigin=$Get(%request.CgiEnvs("HTTP_ORIGIN"))

     #; Allow requested origin
     Do ..SetResponseHeaderIfEmpty("Access-Control-Allow-Origin",tOrigin) 

以下几行指定应包含授权标头。

    #; Set allow credentials to be true
    Do ..SetResponseHeaderIfEmpty("Access-Control-Allow-Credentials","true")

以下行从传入请求中获取标头和请求方法。代码应测试是否允许标头和请求方法。如果允许,请使用它们来设置响应标头。如果不是,请将响应标头设置为空字符串。

    #; Allow requested headers
    Set tHeaders=$Get(%request.CgiEnvs("HTTP_ACCESS_CONTROL_REQUEST_HEADERS"))
    Do ..SetResponseHeaderIfEmpty("Access-Control-Allow-Headers",tHeaders)

    #; Allow requested method
    Set tMethod=$Get(%request.CgiEnvs("HTTP_ACCESS_CONTROL_REQUEST_METHOD"))
    Do ..SetResponseHeaderIfEmpty("Access-Control-Allow-Method",tMethod)

重要提示:默认 CORS 标头处理不适用于处理机密数据的 REST 服务。

修改规范类

在定义 %CSP.REST 的自定义子类(包括 OnHandleCorsRequest() 的实现)后,执行以下操作:

  1. 编辑规范类中的 OpenAPI XData 块,使 info 对象包含一个名为 x-ISC_DispatchParent 的新属性。此属性的值必须是自定义类的完全限定名称。

例如,假设 OpenAPI XData 块如下所示:

  "swagger":"2.0",
  "info":{
    "version":"1.0.0",
    "title":"Swagger Petstore",
    "description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
    "termsOfService":"http://swagger.io/terms/",
    "contact":{
      "name":"Swagger API Team"
    },
...

假设 %CSP.REST 的自定义子类名为 test.MyDispatchClass。在这种情况下,将修改 XData 块,如下所示:

  "swagger":"2.0",
  "info":{
    "version":"1.0.0",
    "title":"Swagger Petstore",
    "description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
    "termsOfService":"http://swagger.io/terms/",
    "x-ISC_DispatchParent":"test.MyDispatchClass",
    "contact":{
      "name":"Swagger API Team"
    },
...
  1. 编译规范类。此操作重新生成调度类。会注意到该类现在扩展了自定义调度超类。因此它将使用 OnHandleCorsRequest() 方法。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容