#身份认证

0 关注者 · 8 帖子

与计算机有关的身份认证是指验证用户或进程身份的过程或操作。

有关 InterSystems 数据平台中身份验证的文档

文章 Kelly Huang · 六月 5, 2025 7m read

在过去的几个月里,我一直在从事 SMART on FHIR EHR Launch 的工作,使用 CSIRO 的两个开源应用程序:SMART-EHR-Launcher 和 SMART 表单应用程序来测试 IRIS for Health 的功能。这段旅程非常有趣,我非常感谢能有机会参与这项任务并探索 IRIS for Health 的更多潜力。

在 HL7 AU FHIR Connectathon 上成功演示了多个外部 SMART 应用程序的无缝启动后,我很高兴能与社区分享我的心得。我希望我的见解能帮助其他人更快地开始类似的项目。

这项任务涉及使用 SMART-EHR-Launcher 作为 EHR 来启动 SMART 表单应用程序。同时,IRIS for Health 被用作 EHR 的 FHIR 资源库,其 OAuth2 服务器被用作授权服务器。

在进入激动人心的时刻之前,让我们先仔细了解一下 SMART on FHIR 和 SMART on FHIR EHR 启动仪式。让我们问问我们的好朋友 ChatGPT 和 豆包。

什么是 SMART on FHIR?

SMART on FHIR 是一种用于开发医疗保健应用程序的平台,旨在实现医疗保健系统之间的互操作性、安全性和可扩展性。以下是其详细介绍:

0
1 75
文章 姚 鑫 · 二月 2, 2025 3m read

第十三章 I 开头的术语

安装目录 (install-dir)

系统

在通用引用 IRIS 安装目录时,文档使用术语 install-dir。在示例中,文档使用 C:\MyIRIS\。章节“默认安装目录”描述了 IRIS 在所有受支持操作系统上的安装位置。

实例 (instance)

对象(Objects)

表示特定实体的类的实现。术语“实例”和“对象”可以互换使用。

实例认证 (Instance Authentication)

系统

本地认证系统:用户会被提示输入密码,输入的密码的哈希值会传递到 IRIS 服务器,并与服务器中存储的现有密码的哈希值进行比较。如果两个值相同,IRIS 将授予用户对其有权限的资源的访问权限。

此机制在管理门户中列为“密码认证”。

实例方法 (instance method)

对象(Objects)

从类的特定实例调用的方法,并执行与该实例相关的某些操作。

实例化 (instantiate)

对象(Objects)

将对象实例放入内存中,以便程序可以对其进行操作。

中间源代码 (intermediate source code)

ObjectScript

IRIS 中可用的标准三代语言(3GLObjectScript 源代码。中间代码由 IRIS 编译器从宏源生成。在这个阶段,所有预处理器语法(包括嵌入式 SQL)都已解析,例程仅包含纯源代码。可以在这个级别编写 ObjectScript 例程,但无法使用嵌入式 SQL 或其他预处理器语法(如宏)。

InterSystems IRIS 启动器 (InterSystems IRIS launcher)

系统

Windows 系统上启动IRIS 时显示在任务栏上的图标。通过此图标,你可以配置和管理IRIS 系统,以及创建和管理类和例程。

InterSystems IRIS 数据库 (InterSystems IRIS database)

系统

存储在单个目录、命名空间或 UIC 中的全局和例程中的相关数据集合。

InterSystems IRIS Java 对象服务器 (InterSystems IRIS Object Server for Java)

对象(Objects)

IRIS Java 绑定允许用 Java 编写的客户端应用程序访问基于服务器的 IRIS 对象。

InterSystems IRIS 对象实用库 (InterSystems IRIS object utility library)

对象(Objects)

IRIS 对象实用库提供了一个接口,用于配置 IRIS 的对象组件、操作和编译类以及交互式使用对象。这些实用工具的主要接口是通过 %SYSTEM.OBJO 类。

InterSystems IRIS 关系实用库 (InterSystems IRIS relational utility library)

InterSystems SQL

IRIS 关系实用库提供了一个接口,用于配置 SQL、管理 SQL 服务器以及从其他关系数据库导入 DDL。 这些实用工具的主要接口是通过 %SYSTEM.SQL 类。

InterSystems IRIS 服务器 (InterSystems IRIS server)

系统

允许你在网络系统中使用分布式 IRIS 数据库的设施。

0
0 78
文章 Weiwei Gu · 九月 14, 2023 1m read

昨天,我在一个客户网站提供从 Studio 迁移到 VS Code 的定制咨询时,就遇到了这种情况。

该站点的服务器已配置为使用delegated authentication,但尚未针对 /api/atelier Web 应用程序设置“delegated”复选框,而 InterSystems ObjectScript 扩展包的成员正是使用该复选框进行连接的。

一旦我们的应用程序设置了其复选框并单击了服务器管理器刷新按钮,就可以在服务器上枚举命名空间。

0
0 147
文章 Michael Lei · 六月 26, 2022 3m read

在这篇文章中,我将解释如何通过使用CSP Web应用程序以及启用/禁用和认证/取消认证任何Web应用程序的代码来进行认证、授权和审计。

应用层
 

0
0 181
问题 Michael Lei · 四月 21, 2021

大家好,

我正在创建WS做服务器用,但是当我要求WSDL时,提示错误因为找不到类。
我添加了以下说明:

set ^SYS("Security","CSP","AllowClass","MiProyecto.MiClaseWS","%SOAP.WebServiceInfo")=1 
set ^SYS("Security","CSP","AllowClass","MiProyecto.MiClaseWS","%SOAP.WebServiceInvoke")=1

我已经在WS安全配置中创建了一个入口

在“应用程序角色”选项卡中,我配置了%All权限

(图像中的命名空间“Samples”是出于安全原因)

如果我以以下方式调用服务,则http:// localhost:57772 / myproject / ws / MyProject.MiClassWS.cls? WSDL提示以下错误:

Not Found
The requested URL /miproyecto/ws/MiProyecto.MiClaseWS.cls was not found on this server.

但是,另一方面,如果我执行以下命令,它可以正常工作: https:// localhost:57772 / csp / sample / MiProyecto.MiClaseWS.cls?wsdl

1
0 286
文章 Nicky Zhu · 二月 4, 2021 7m read

上一篇: IRIS中的权限管理

在上一篇文章中,我们介绍了IRIS中的权限控制体系。在本文中我们将以一个常见的实施需求为例介绍如何使用IRIS的权限配置出一个只能使用SQL的用户。

需求的分解

和所有用户需求一样,当用户提出一个需求时,除其语义显式的含义之外,还需分析其是否具有没有明确说明的含义。 对于一个只能使用SQL的用户这样一个需求,即应当结合平台的特征分解成为功能需求: 具有一个合法,可通过用户名和密码使用IRIS的用户 该用户的数据库权限

  • 确认项:可以使用SQL访问所有数据库还是某几个特定的数据库? 该用户的SQL权限
  • 确认项:对于特定的数据库,是否可以执行所有的DDL?
  • 确认项:对于特定的数据库,是否对每一张表都可以执行Select、Update等所有的DML 该用户的程序权限
  • 确认项:用户是否可以通过Portal登录并管理IRIS?

如上所示,一个只能使用SQL的用户,这样一个看似简单的需求,如果需要与用户获得一致的理解并付诸实施,则需要将其分解,对于没有在用户需求中明确约定的部分,应作为待确认项与用户确认。 另外,需要注意的是,IRIS作为一个数据平台,除了提供底层的数据库之外,也提供了Portal等Web应用程序便于使用Sharding、HA、Interoperability等平台功能,通过平台对外提供的Webservice、REST等web接口也受Web应用程序控制。因此,当需要设计权限体系时,不但需要考虑用户使用的数据库相关的权限,也需要考虑是否需要控制Web应用程序的权限。

我们假设需要提供一个严格意义上的只能对某个库的某个Schema下的所有表具有只读权限的用户,即: 具有一个合法,可通过用户名和密码使用IRIS的用户 该用户的数据库权限

  • 该用户只能使用DemoSpace命名空间下的数据库 该用户的SQL权限
  • 该用户不能执行任何DDL
  • 该用户只能对DemoSchema下的所有表执行Select语句 该用户的程序权限
  • 该用户不能登录Portal,不能执行Portal中提供的任何管理功能

对数据库的配置

在IRIS中创建数据库时,默认的行为是引用%DB_%DEFAULT这个资源,并引用%DB_%DEFAULT角色(注意,平台中有一个叫做%DB_%DEFAULT的资源,同时还有一个叫做%DB_%DEFAULT的角色。%DB_%DEFAULT角色通过%DB_%DEFAULT资源获得默认的数据库访问权限)。如果直接使用%DB_%DEFAULT角色或%DB_%DEFAULT资源,都有可能影响到之前以默认配置创建的数据库,因此,在需要细粒度控制访问权限时,往往需要自定义资源和角色实现。

创建资源%DB_DemoDB_Res {#3.1}

资源可在创建数据库的同时创建,也可以在使用默认资源创建数据库之后,再给数据库指派其他资源。本例中,我们在创建命名空间DEMOSPACE的同时创建数据库DEMODB并创建资源。 image

创建角色DemoDB_Read_Role {#3.2}

image 在创建角色之后,即可为其分配资源。根据资源类型的不同,对资源的操作可以有读、写和使用三种权限。对于数据库引用的资源,是读权限和写权限。在本例中,我们需要创建的是只读用户,因此,资源权限分配读权限即可,不用赋写权限。 image

创建用户DemoUser并分配角色

通过Portal创建用户之后,即可给用户分配角色。在本例中,需要给这个用户分配之前创建的DemoDB_Read_Role角色。 image 在经过上述配置之后,用户DemoUser即已拥有对命名空间DEMOSPACE中数据库的访问权限。 image 此时,用户对数据库拥有读权限,但并没有对表执行查询或建表的权限,如果尝试create table,则会得到如下的权限错误信息: image 为继续实验,我们通过Portal执行这SQL语句先创建DemoSchema.Persons这张表 image

为角色DemoDB_Read_Role分配SQL权限

由于用户具有的权限不足,无法执行SQL操作,因此我们需要对该用户的角色赋予对应的权限(或直接给用户赋权,但平台用户较多时,考虑到用户管理的成本,并不推荐这样做)。可以采用如下手段进行SQL的授权

通过Portal授权

在Portal的用户管理和角色管理功能中,均可指定要授予的SQL权限。 SQL特权栏用于对DDL进行数据库级的授权,例如对DEMOSPACE命名空间下的数据库分配建表、修改表、建视图等DDL操作。在本例中,用户不具有这些权限,因此不对该用户对应的角色授予这些权限。 image 在SQL表,SQL视图和SQL过程栏中,则是分别对表、视图和存储过程授予查询、执行等权限。在本例中,用户需要对DemoSchema这个Schema下的表拥有select查询权限,即可通过对SQL表授权进行 image 授权后该角色的SQL表权限如下 image 此时通过SQL工具已可执行查询 image 使用Portal授权时是针对单个的表、视图或存储过程进行。在上例中,我们单独对表DemoSchema.Persons进行了授权,如果我们再建立一张DemoSchema.Employee表,当前的角色和用户并不能自动获得读取其数据的权限。

通过SQL授权

超级管理员或拥有SQL授权权限的用户可以通过SQL的GRANT语句对数据库对象(包括库,函数,表,视图和存储过程等)进行授权,SQL GRANT语句的语法和使用详见GRANT,此处不再赘述。 在上面的例子中我们建立了表DemoSchema.Persons,建表的同时建立的Schema DemoSchema。假如现在我们希望对授权进行简化,使角色DemoDB_Read_Role可以直接获得Schema下所有表的读权限,则可以用如下的SQL:

GRANT SELECT ON SCHEMA DemoSchema to DemoDB_Read_Role

执行成功后再查看DemoDB_Read_Role的SQL权限,会发现: image 即这个角色已经拥有了Schema级的授权,因此,对整个Schema下的所有表都拥有权限。之后在Schema中如果建立了新的表,则这个角色会自动拥有这些表的读权限。

限制用户登录和使用Portal

上例配置的用户可以用于登录IRIS的Portal,但由于没有任何系统功能的权限,不能执行操作。 image IRIS的Web应用程序在创建时默认并不需要额外的资源去访问,这意味着所有合法用户都能登入这个Web应用,但由于支撑应用的后台程序和数据是受到资源的保护的,能登入的用户不一定具有运行程序、访问数据的权限,正如我们建立的用户DemoUser可以登录Portal,但没有功能菜单可用。 如果需要进一步限制用户的行为,禁止其登录,则还需要对应用权限进行控制。 如我们在上一篇文章:IRIS中的权限管理 中所述,Portal是平台提供的Web应用程序,是通过Web应用的权限控制可访问性,因此,需要修改应用的资源要求。 通过菜单: 系统管理 > 安全 > 应用程序 > Web应用程序 可以访问当前系统提供的Web应用列表,其中的/csp/sys即为系统管理门户Portal image 其中必要的资源一栏即为该应用的资源需求,默认为空,即访问该应用不需要特定资源,只要是合法用户即可。我们可以为该应用指定所需资源,例如%Development,即只有具有%Development资源的角色及其对应的用户才能够访问该程序。保存设置后,再尝试以用户DemoUser登录Portal,结果是 image 除非我们为DemoUser引用的角色DemoDB_Read_Role分配资源%Development,该用户都不能登录。 当然,超级管理员由于拥有所有权限,不受这个设置的影响。

总结

通过上述实验,我们创建了一个用户,只能使用SQL连入并查询指定Schema下的表。希望通过这个实验,大家能够掌握IRIS权限管理的基本元素:

  • 用户,角色,权限,资源和许可构成的权限控制体系
  • 数据库、SQL和应用程序都是权限管理的对象

大家在实际项目中可以根据最终用户的实际需要,灵活应用这些概念,构建满足需求的权限配置。

上一篇: IRIS中的权限管理

3
1 448
文章 Nicky Zhu · 二月 3, 2021 6m read

下一篇: 案例: 建立只能使用SQL的用户

IRIS通过认证(Authentication)与授权(Authorization)两项机制控制外部用户对系统及应用、数据资源的可访问性。因此。如需要进行权限控制,则需要通过配置认证和授权进行。

IRIS中的认证 {#2}

认证可以验证任何试图连接到InterSystems IRIS®的用户的身份。一旦通过认证,用户就与IRIS建立了通信,从而可以使用其数据和工具。有许多不同的方法可以验证用户的身份;每种方法都称为验证机制。IRIS 通常被配置为只使用其中一种方式。 支持的认证方式

  • 实例认证:通过用户名/密码对登录平台,即密码认证
  • LDAP:通过第三方LDAP服务器(如Windows Active Directory )完成认证
  • 操作系统认证:建立操作系统用户-平台用户映射,使用操作系统用户登录平台
  • Kerberos:使用Kerberos协议进行认证
  • 代理认证:使用自定义的代码实现认证过程

系统服务与认证 {#2.1}

在安装时,IRIS会启动一系列系统级的服务用与控制与外部用户或系统的交互,这些服务都绑定了默认的认证机制 image 图中红框标出的即为系统安装后会自动启用并需经认证才可使用的系统服务,认证手段可配置。 例如,如果变更%Service_Console的身份验证方法,取消密码方法,用户就不能通过输入用户名密码登入Terminal。 通过Portal的菜单 系统管理 > 安全 > 服务 可访问该设置。

账户控制参数 {#2.2}

通过系统管理 > 安全 > 系统安全 > 系统范围的安全参数中的选项可对于用户名/密码认证手段的行为进行更多的约束。 image

  • 非活动限制 - 指定用户账户不活跃的最大天数,它被定义为成功登录之间的时间。当达到此限制时,该帐户将被禁用。值为0(0)表示对登录之间的天数没有限制。[对于最低安全级别的安装,默认为0,对于正常和锁定的安装,默认为90]。
  • 无效登录限制 (0-64) - 指定连续不成功的登录尝试的最大次数。在达到此限制后,要么禁用账户,要么对每次尝试进行递增的时间延迟;行动取决于如果达到登录限制字段则禁用账户的值。值为0(零)表示对无效登录的次数没有限制。[默认为5]
  • 如果达到登录限制,则禁用账户 - 如果选中,则指定达到无效登录次数(在前一字段中指定)将导致用户账户被禁用。
  • 密码有效期天数(0-99999) - 指定密码过期的频率以及用户更改密码的频率(天数)。当初始设置时,指定密码过期的天数。0(0)表示密码永远不会过期。不会影响已设置了下次登录时更改密码字段的用户。[默认为0]

需要特别注意的是,密码有效性、过期和禁用账户等设置会影响IRIS实例的所有账户,包括IRIS超级管理员账户。如触发了控制策略,则在更新这些帐户的信息之前,可能无法进行各种操作,这可能导致意外的结果。如超级管理员账户被锁定,则需要通过紧急模式启动实例再进行修改。

对于系统可用的认证手段的配置和其他可用的安全配置,请参见Security Administration Guide

IRIS中的授权 {#3}

授权模型 {#3.1}

InterSystems公司的授权模式采用基于角色的访问控制。

  • Users – 用户
  • Roles – 角色
  • Privileges – 权限
  • Resources – 资源 | Permissions – 许可

在这种模式下,用户拥有与分配给各自用户身份的角色相关的权限。 image

  • 一个角色是一个命名的特权集合
  • 一个用户可以拥有一个以上的角色
  • 权限分配给角色,角色分配给用户

其中,Roles就是权限的集合,而权限提供对资源的特定类型的访问的许可。

  • 可控资源: 数据库,服务,应用(包括Web应用 )和其他
  • 可选用的许可: Read, Write or Use,其中执行代码需要数据库的读权限

资源的定义 {#3.2}

资源是一项相对抽象的概念,用来指代IRIS中的数据库,服务,应用等可被访问的对象。例如,对于数据库,在建立时默认采用%DB_%DEFAULT指代,也可自定义资源(数据库资源必须以%DB_开头): image

对于Web应用,默认不需要通过资源控制,即所有可登录用户都可访问(但该用户进程不一定能访问到数据,还需参照是否具有对数据库的访问权限)。如通过分配资源进行控制,则登录用户还需具有资源才能访问这个Web应用: image

因此,一项权限实际上是指对某个资源的一些特定操作的集合。 例如,对于数据库UserDB具有读写操作许可的权限A,对于Web应用/csp/sys具有使用操作许可的权限B。如果我们将这两项权限都赋给角色RoleA,那么这个角色就同时拥有A权限和B权限,从而能够访问数据库UserDB和访问Web应用/csp/sys。

SQL授权 {#3.3}

除了对数据库进行授权外,IRIS作为一个数据平台,需要对外提供数据访问。因此,IRIS也提供了SQL授权对用户可执行的SQL进行细粒度的权限控制。 SQL的授权可以分配给角色或用户。但通常在企业环境中,用户数量会很多,仍然需要对SQL用户进行分组,根据分组规划角色,通过角色进行授权的控制,才能有效降低维护授权所需的工作量。 SQL的授权针对SQL类型,可分为库、表级授权。 对于Create table、drop view、truncate table这一类的DDL,使用库级授权,即用户可在特定的库中执行建表、删除视图等经过授权的操作。如下: image

对于Select、update等DML,则使用表级授权,使用户能够通过DML访问特定的表中的数据。如下: image

除通过Portal操作之外,对于SQL的授权,还可使用IRIS SQL中的额GRANT语句,例如:

GRANT * ON Schema Test TO TestRole

这个SQL即可以将当前操作数据库下Schema Test中的所有表的所有权限都赋给TestRole这个角色。 关于GRANT语句的用法,可参见GRANT指令

以上即为IRIS中进行权限控制所需掌握的概念和内容,在后续文章中,我们会结合实例向大家介绍其使用。

下一篇: 案例: 建立只能使用SQL的用户

推荐阅读

Security Administration Guide - https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCAS

0
0 651
文章 Qiao Peng · 一月 14, 2021 12m read

本文以及后面两篇该系列文章,是为需要在其基于 InterSystems 产品的应用程序中使用 OAuth 2.0 框架(下文简称为 OAUTH)的开发人员或系统管理员提供的指南。

作者:InterSystems 高级销售工程师 Daniel Kutac

发布后校正和更改历史记录

  • 2016 年 8 月 3 日 - 修正了 Google 客户端配置屏幕截图,更新了 Google API 屏幕截图以反映新版本的页面
  • 2016 年 8 月 28 日 - 更改了 JSON 相关代码,反映了对 Cache 2016.2 JSON 支持的更改
  • 2017 年 5 月 3 日 - 更新了文本和屏幕,以反映 Cache 2017.1 的新 UI 和功能
  • 2018 年 2 月 19 日 - 将 Caché 更改为 InterSystems IRIS 以反映最新的发展。 但是请记住,尽管产品名称发生更改,但文章涵盖所有的 InterSystems 产品——InterSystems IRIS 数据平台、Ensemble 和 Caché。
  • 2020 年 8 月 17 日 - 大面积更改,软件方面更改更大。 要获取 Google 的更新版 Oauth2 的网址,请咨询 Micholai Mitchko。

第 1 部分 客户端

简介

有关开放式授权框架 InterSystems 实现的相关内容,我们分 3 部分讲述,这是第 1 部分。

在第 1 部分中,我们对该主题进行了简短介绍,并提供了一个 InterSystems IRIS 应用程序担当授权服务器客户端并请求一些受保护资源的简单方案。

第 2 部分将讲述一个复杂一些的方案,在该方案中 InterSystems IRIS 本身通过 OpenID Connect 担当授权服务器和身份验证服务器。

本系列的最后一部分将描述 OAUTH 框架类的各个部分,它们由 InterSystems IRIS 实现。

什么是开放授权框架 [1]

许多人已经听说过有关开放授权框架及其用途的信息。 因此这里只做简单介绍,以备未听说过的人参考。

开放授权框架 (OAUTH) 当前为 2.0 版,其是一种协议,允许基于 Web 的主应用程序通过在客户端(应用程序请求数据)和资源所有者(应用程序保存请求的数据)之间建立间接信任来以安全的方式交换信息。 信任本身由客户端和资源服务器都认可并信任的主体提供。 该主体称为授权服务器。

简单举例如下:

假设 Jenny(使用 OAUTH 术语,就是资源所有者)在开展 JennyCorp 公司的一个工作项目。 她为一个潜在的大型业务创建了项目计划,并邀请 JohnInc 公司的业务伙伴 John(客户端用户)审阅此文档。 不过,她并不愿意让 John 访问自己公司的 VPN,因此她将文档放在 Google 云端硬盘(资源服务器)或其他类似的云存储中。 她这样做,已经在她和 Google(授权服务器)之间建立了信任。 她标记了要与 John 共享的文档(John 已经使用 Google 云端硬盘服务,Jenny 知道他的电子邮件)。

当 John 想要阅读该文档时,他进行了 Google 帐户身份验证,然后通过移动设备(平板电脑、笔记本电脑等)启动文档编辑器(客户端服务器)并加载 Jenny 的项目文件。

这听起来很简单,但是两个人与 Google 之间有很多通信。 所有交流均遵循 OAuth 2.0 规范,因此 John 的客户端(阅读器应用程序)必须首先向 Google 进行身份验证(OAUTH 不涵盖此步骤),然后 John 申请获取 Google 对提供表格的同意,经过授权后,Google 就会发出一个访问令牌,授权阅读器应用程序访问文档。 阅读器应用程序使用该访问令牌向 Google 云端硬盘服务发出请求,以检索 Jenny 的文件。

下图说明了各方之间的通信

请注意:虽然所有的 OAUTH 2.0 通信都使用 HTTP 请求,但服务器不必非得是 Web 应用程序。

让我们通过 InterSystems IRIS 来说明这一简单方案。

简单 Google 云端硬盘演示

在本演示中,我们将创建一个基于 CSP 的小型应用程序,该应用程序将使用我们自己的帐户(以及作为奖励的日历列表)来请求存储在 Google 云端硬盘服务中的资源(文件列表)。

基本要求

开始应用程序编码之前,我们需要准备环境。 这包括启用 SSL 的 Web 服务器和 Google 配置文件。

Web 服务器配置

如上所述,我们需要使用 SSL 与授权服务器进行通信,因为默认情况下 OAuth 2.0 要求如此。 我们需要确保数据安全,对吧?

解释如何配置 Web 服务器来支持 SSL 的内容超出了本文讨论的范围,因此,请以您喜欢的方式参阅相应 Web 服务器的用户手册。 为了您的好奇心(我们稍后可能会显示一些屏幕截图),在此特定示例中,我们将使用 Microsoft IIS 服务器。

Google 配置

为了向 Google 注册,我们需要使用 Google API Manager- https://console.developers.google.com/apis/library?project=globalsummit2016demo

为了进行演示,我们创建了一个帐户 GlobalSummit2016Demo。 确保我们已启用 Drive API

现在,该定义凭据了

请注意以下事项:

_Authorized JavaScript – _我们仅允许本地生成的脚本(相对于调用页面)

_Authorized redirect URIs – 从理论上讲,我们可以将客户端应用程序重定向到任何站点,但是当使用 InterSystems IRIS OAUTH 实现时,我们必须重定向到** https://localhost/csp/sys/oauth2/OAuth2.Response.cls**。您可以定义多个授权的重定向 URI,如屏幕截图所示,但是对于本演示,我们只需要两者中的第二个条目。

最后,我们需要将 InterSystems IRIS 配置为 Google 授权服务器的客户端

Caché /IRIS配置

InterSystems IRIS OAUTH2 客户端配置需要两步。 首先,我们需要创建服务器配置。

在 SMP 中,导航至系统管理 > 安全性 > OAuth 2.0 > 客户端配置

点击创建服务器配置按钮,填写表格并保存。

输入到表格的所有信息可以在 Google 开发者控制台网站上找到。 请注意,InterSystems IRIS 支持自动 Open ID 发现。 但是,由于我们没有使用它,因此我们手动输入所有信息

现在,点击新创建的 Issuer Endpoint
旁边的“客户端配置”链接。并点击创建客户端配置按钮。

将“客户端信息”和“JWT 设置”选项卡保留为空(默认值),并填写客户端凭据。

请注意:我们正在创建机密客户端(这比公共客户端更安全,这意味着客户端秘密永远不会离开客户端服务器应用程序(永远不会传输到浏览器)

此外,请确保选中**“使用 SSL/TLS**”,并提供主机名(本地主机,因为我们将本地重定向到客户端应用程序),最后提供端口和前缀(当同一台机器上有多个 InterSystems IRIS 实例时,这非常有用)。 根据输入的信息,会计算客户端重定向 URL 并显示在上一行中。

在上面的屏幕截图中,我们提供了一个名为 GOOGLE 的 SSL 配置。 该名称本身实际上仅用于帮助您确定此特定通信通道使用的可能是众多 SSL 配置中的哪个。 Caché 使用 SSL/TLS 配置存储所有必要的信息,以建立与服务器(在本例中,为 Google OAuth 2.0 URI)的安全流量。

有关详细信息,请参阅文档 。

Supply Client ID 和 Client Secret 值从 Google 凭据定义表中获得(使用手动配置时)。

现在,我们完成了所有的配置步骤,可以开始编写 CSP 应用程序代码。

客户端应用程序

客户端应用程序是基于 Web 的简单 CSP 应用程序。 因此,它包含由 Web 服务器定义和执行的服务器端源代码,以及由 Web 浏览器向用户公开的用户界面。 下文提供的示例代码期望客户端应用程序在 GOOGLE 名称空间中运行。 请将路径 /csp/google/ 修改为您的命名空间。

客户端服务器

客户端服务器是一个简单的两页应用程序。 在该应用程序内,我们将:

·        将 URL 重定向到 Google 授权服务器

·        执行向 Google Drive API 和 Google Calendar API 的请求并显示结果

第 1 页

这是应用程序的一页,我们决定在此处调用 Google 的资源。

以下是此页面上简单但功能齐全的代码。

<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">Class Web.OAUTH2.Google1N Extends %CSP.Page</font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">{</font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">Parameter OAUTH2CLIENTREDIRECTURI = "https://localhost/csp/google/Web.OAUTH2.Google2N.cls";</font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">Parameter OAUTH2APPNAME = "Google";</font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">ClassMethod OnPage() As %Status</font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">{</font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>&html<</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial"></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial"></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">        </span><!-- insert the page content here --></font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">        </span><h1>Google OAuth2 API</h1></font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">        </span><p>This page demo shows how to call Google API functions using OAuth2 authorization.</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">        </span><p>We are going to retrieve information about user and his/her Google Drive files as well as calendar entries.</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">        </span>></font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><span style="margin: 0px;"><font color="#000000" face="Arial">        </font></span></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>// we need to supply openid scope to authenticate to Google</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>set scope="openid https://www.googleapis.com/auth/userinfo.email "_</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>"https://www.googleapis.com/auth/userinfo.profile "_</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>"https://www.googleapis.com/auth/drive.metadata.readonly "_</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>"https://www.googleapis.com/auth/calendar.readonly"</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>set properties("approval_prompt")="force"</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>set properties("include_granted_scopes")="true"</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(..#OAUTH2APPNAME,scope,</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>..#OAUTH2CLIENTREDIRECTURI,.properties,.isAuthorized,.sc) </font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>w !,"<p><a href='"_url_"'><img border='0' alt='Google Sign In' src='images/google-signin-button.png' ></a>" </font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>&html<</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>Quit $$$OK</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">}</font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]</font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">{</font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>#dim %response as %CSP.Response</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>set scope="openid https://www.googleapis.com/auth/userinfo.email "_</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>"https://www.googleapis.com/auth/userinfo.profile "_</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>"https://www.googleapis.com/auth/drive.metadata.readonly "_</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>"https://www.googleapis.com/auth/calendar.readonly"</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>if ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,scope,.accessToken,.idtoken,.responseProperties,.error) {</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>set %response.ServerSideRedirect="Web.OAUTH2.Google2N.cls"</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>}</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>quit 1</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>}</font></font></span>
<span style="margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">}</font></span>

代码的简要说明如下:

1.      OnPreHTTP 方法 - 首先,我们有机会时检查一下,我们是否由于 Google 授权而获得了有效的访问令牌——这种情况可能会发生,例如当我们只是刷新页面时。 如果没有,我们需要授权。 如果我们有令牌,我们只需将页面重定向到显示结果的页面

2.       OnPage 方法 - 只有在我们没有可用的有效访问令牌时,我们才到这里,因此我们需要开始通信——向 Google 进行身份验证和授权,以便它向我们授予访问令牌。

3.       我们定义了作用域字符串和属性数组,用于修改 Google 身份验证对话框的行为(我们需要先向 Google 进行身份验证,然后它才能根据我们的身份对我们进行授权)。

4.       最后,我们收到 Google 登录页面的 URL,然后将其提供给用户,接着提供同意页面。

还有一点注意事项:

我们在 OAUTH2CLIENTREDIRECTURI 参数的 https://www.localhost/csp/google/Web.OAUTH2.Google2N.cls 中指定真正的重定向页面。 但是,我们在 Google 凭据定义中使用了 InterSystems IRIS OAUTH 框架的系统页面! 重定向由我们的 OAUTH 处理程序类在内部处理。

第 2 页

此页面显示 Google 授权的结果,如果成功,我们将调用 Google API 调用以检索数据。 同样,此代码简单,但功能齐全。 相比读者的想象,我们以更结构化的方式来显示输入数据。

<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">Include %occInclude</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">Class Web.OAUTH2.Google2N Extends %CSP.Page</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">{</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">Parameter OAUTH2APPNAME = "Google";</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">Parameter OAUTH2ROOT = "https://www.googleapis.com";</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">ClassMethod OnPage() As %Status</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">{</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>&html<</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">   </span></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">   </span>></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>// Check if we have an access token</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>set scope="openid https://www.googleapis.com/auth/userinfo.email "_</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>"https://www.googleapis.com/auth/userinfo.profile "_</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>"https://www.googleapis.com/auth/drive.metadata.readonly "_</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>"https://www.googleapis.com/auth/calendar.readonly"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>set isAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,scope,.accessToken,.idtoken,.responseProperties,.error)</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>if isAuthorized { </font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>// Google has no introspection endpoint - nothing to call - the introspection endpoint and display result -- see RFC 7662.<span style="margin: 0px;">  </span></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>w "<h3>Data from <span style='color:red;'>GetUserInfo API</span></h3>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>// userinfo has special API, but could be also retrieved by just calling Get() method with appropriate url<span style="margin: 0px;">    </span></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>try {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>set tHttpRequest=##class(%Net.HttpRequest).%New()</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>$$$THROWONERROR(sc,##class(%SYS.OAuth2.AccessToken).AddAccessToken(tHttpRequest,"query","GOOGLE",..#OAUTH2APPNAME))</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>$$$THROWONERROR(sc,##class(%SYS.OAuth2.AccessToken).GetUserinfo(..#OAUTH2APPNAME,accessToken,,.jsonObject))</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>w jsonObject.%ToJSON()</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>} catch (e) {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>w "<h3><span style='color: red;'>ERROR: ",$zcvt(e.DisplayString(),"O","HTML")_"</span></h3>"<span style="margin: 0px;">    </span></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>}</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>/******************************************</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>*<span style="margin: 0px;">                                         </span>*</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>*<span style="margin: 0px;">      </span>Retrieve info from other APIs<span style="margin: 0px;">      </span>*</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>*<span style="margin: 0px;">                                         </span>*</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>******************************************/</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>w "<hr>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>do ..RetrieveAPIInfo("/drive/v3/files")</font></font></span>
<font color="#000000" face="Arial" size="2"> </font>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>do ..RetrieveAPIInfo("/calendar/v3/users/me/calendarList")</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>} else {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>w "<h1>Not authorized!</h1>"<span style="margin: 0px;">  </span></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>}</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>&html<</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>Quit $$$OK</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">}</font></span>
<font color="#000000" face="Arial" size="2"> </font>

<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">ClassMethod RetrieveAPIInfo(api As %String)</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">{</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>w "<h3>Data from <span style='color:red;'>"_api_"</span></h3><p>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>try {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>set tHttpRequest=##class(%Net.HttpRequest).%New()</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>$$$THROWONERROR(sc,##class(%SYS.OAuth2.AccessToken).AddAccessToken(tHttpRequest,"query","GOOGLE",..#OAUTH2APPNAME))</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>$$$THROWONERROR(sc,tHttpRequest.Get(..#OAUTH2ROOT_api))</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>set tHttpResponse=tHttpRequest.HttpResponse</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>s tJSONString=tHttpResponse.Data.Read()</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>if $e(tJSONString)'="{" {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>// not a JSON</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>d tHttpResponse.OutputToDevice()</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>} else {<span style="margin: 0px;">      </span></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>w tJSONString</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>w "<hr/>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>/*</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>// new JSON API</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>&html<<table border=1 style='border-collapse: collapse'>></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>s tJSONObject={}.%FromJSON(tJSONString)</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span>set iterator=tJSONObject.%GetIterator()</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">        </span>while iterator.%GetNext(.key,.value) {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">          </span>if $isobject(value) {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">      </span><span style="margin: 0px;">      </span>set iterator1=value.%GetIterator()</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">            </span>w "<tr><td>",key,"</td><td><table border=1 style='border-collapse: collapse'>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">            </span>while iterator1.%GetNext(.key1,.value1) {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">            </span>if $isobject(value1) {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">                </span>set iterator2=value1.%GetIterator()</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">                </span>w "<tr><td>",key1,"</td><td><table border=0 style='border-collapse: collapse'>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">                </span>while iterator2.%GetNext(.key2,.value2) {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">                    </span>write !, "<tr><td>",key2, "</td><td>",value2,"</td></tr>"<span style="margin: 0px;">                   </span></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">                </span>}</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">                </span>// this way we can go on and on into the embedded objects/arrays</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">              </span>w "</table></td></tr>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">            </span>} else {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span><span style="margin: 0px;">                </span>write !, "<tr><td>",key1, "</td><td>",value1,"</td></tr>"<span style="margin: 0px;">       </span></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">            </span>}</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">            </span>}</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">          </span>w "</table></td></tr>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">          </span>} else {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">              </span>write !, "<tr><td>",key, "</td><td>",value,"</td></tr>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">          </span>}</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">        </span>}<span style="margin: 0px;">    </span><span style="margin: 0px;">   </span></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>&html<</table><hr/></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>></font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>*/</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>}</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>} catch (e) {</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">    </span>w "<h3><span style='color: red;'>ERROR: ",$zcvt(e.DisplayString(),"O","HTML")_"</span></h3>"</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font face="Arial"><font color="#000000"><span style="margin: 0px;">  </span>}</font></font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">}</font></span>
<span style="background: rgb(242, 242, 242); margin: 0px; line-height: 115%; font-size: 9pt;"><font color="#000000" face="Arial">}</font></span>

 

让我们快速看一下代码:

1.       首先,我们需要检查一下我们是否具有有效的访问令牌(即我们是否被授权)

2.       如果是,我们可以向 Google 提供且由已发布访问令牌覆盖的 API 发出请求

3.       为此,我们使用标准的 %Net.HttpRequest 类,但根据 API 规范,我们将访问令牌添加到 GET 或 POST 方法中

4.       如您所见,为了方便您,OAUTH 框架已实现 GetUserInfo()方法,但是您可以使用 Google API 规范直接检索用户信息,就像我们在 RetrieveAPIInfo()助手方法中所做的一样。

5.       由于在 OAUTH 世界中以 JSON 格式交换数据司空见惯,因此我们只读取传入的数据,然后简单地将其转储到浏览器。 应用程序开发人员可以解析和格式化接收到的数据,以便用户可以看明白。 但这超出了本演示的范围。 (尽管一些代码有注释,显示了如何完成解析。)

下图是一个输出屏幕截图,显示了原始 JSON 数据。

继续阅读第 2 部分,该部分讲述 InterSystems IRIS 担当授权服务器和 OpenID Connect 提供程序相关的内容。

0
0 399