翻译者:syl
校对者:ginkgo
原文链接:https://iiif.io/api/auth/1.0/
本文档状态:
此版本:1.0.0
最新稳定版本:1.0.0
上一版本:0.9.4
编辑:
- Michael Appleby
, 耶鲁大学
- Tom Crane
, Digirati
- Robert Sanderson
, J. Paul Getty Trust
- Jon Stroop
, 普林斯顿大学图书馆
- Simeon Warner
,康奈尔大学
版权所有 © 2012-2021 编辑和贡献者。由 IIIF 联盟根据 CC-BY 许可发布,请参阅 免责声明。
1. 引言
IIIF(发音为 “Triple-Eye-Eff”)规范旨在支持对世界各地的资源进行统一和丰富的访问。对内容的开放访问是令人向往的,但内部政策、法律规定、商业模式等限制可能要求用户进行认证,以便授权用户与一些资源进行交互。认证过程可以简单地根据IP地址或点击协议加以限制,也可以根据由安全身份提供者提供的多因素方案。
需要对资源访问加以限制的内容提供者可以提供对可选择版本的分级访问方式,而不是简单的完全允许访问或完全不允许访问。例如,这些可选择的版本可以根据分辨率、水印或压缩来降级,但通常比完全不允许访问要好。
通过运行在web浏览器中的客户端应用程序提供对受限内容的互操作访问这一做法存在许多挑战:
- 一个IIIF 展示 API清单可以引用多个机构的内容资源,这些资源往往来自不同的域。
- 一个资源的各个版本必须有不同的URI,以防止网络缓存提供错误的版本。
- 各机构现有的访问控制系统往往不同。
- 大多数IIIF查看器是客户端的JavaScript应用程序,并可能从一个与它需要加载的图像服务不同的域中提供,因此不受信任。
- 同样地,认证服务的域可能与查看器或基于IIIF的内容的域不同。因此,授权服务器禁止事先了解托管查看器的域。
此外,IIIF社区对本规范有以下目标:
- 不推荐使用IIIF客户端验证用户;托管内容的服务器必须负责从用户处获取凭证,而IIIF查看器不需要了解或访问此交换。
- 基于浏览器的IIIF客户端必须能够在一次认证流程中保持自己的内部状态。
- 不推荐要求注册受信任的域名;任何人都应该能够创建任何类型的查看器并从任何地方运行它。
- 各机构应能使用其现有的认证系统,无需修改。
为了应对这些挑战和目标,IIIF认证规范描述了一套使用现有访问控制系统引导用户的工作流程。验证用户的过程不在此规范的范围之内,它可能涉及到与CAS服务器、OAuth2提供者或是定制的登录系统之间的往返。在此意义上,IIIF认证与CAS等协议不同;前者是一种与任意第三方协议交互的方式。
IIIF认证提供了一个用于登录的用户界面的链接,以及提供凭证的服务(仿照OAuth2工作流程中的元素)。它们一起充当了与服务器的访问控制系统相连的桥梁,而客户端无需了解该系统。
综上所述,本规范描述了如何:
- 在查看器内部,发起与访问控制系统的交互,以便用户能够获得查看受限内容所需的凭证。
- 向客户端提供关于内容提供者的用户状态的必要信息,以提供良好的用户体验。
请将反馈信息发送到 iiif-discuss@googlegroups.com。
1.1 术语
本规范区分了内容资源(如图片或视频)和符合IIIF规范的描述资源(如图像API的图像信息(info.json)和展示API的收藏或清单资源)。从基于浏览器的应用程序的角度来看,内容资源是通过浏览器对HTML元素的解释间接加载的,而描述资源通常是由JavaScript使用XMLHttpRequest接口直接加载。现代浏览器中实施的跨源资源共享(CORS)规范描述了与这两类资源交互时所需遵循的不同安全规则。
下面将介绍另外两个概念,即访问cookie和访问令牌。
本文中的关键词 必须(must/required/shall)、禁止(must not/shall not)、推荐(should/recommended)、不推荐(should not)、 可选(may/optional)按照RFC2119中的描述进行解释。
1.2 内容资源的认证
内容资源,如图像,通常是嵌入网页或应用程序的二级资源。就网页而言,图像可能通过HTML的标签嵌入,并通过浏览器的额外HTTP请求进行检索。当用户没有被授权加载一个网页时,服务器可以将用户重定向到另一个页面,并提供机会进行认证;然而对于嵌入的内容资源,这种重定向是不可能的,用户只会看到一个破损图像的图标。如果图像受到访问控制,浏览器必须通过发送一个cookie来避免破损图像,服务器可以接受这个cookie作为授权访问该图像的凭证。本规范描述了用户获得这种访问cookie的过程。
1.3 描述资源的认证
描述资源,如展示 API清单或图像API信息文档(info.json),为客户端应用程序提供了让浏览器请求内容资源所需的信息。描述资源必须与它所描述的内容资源在同一域中,但不要求执行的客户端代码也托管在这个域中。
浏览器在运行从一个域检索到的JavaScript时,不能使用XMLHttpRequest来加载另一个域的描述资源并在请求中包括该域的cookie而不违反上面介绍的要求,即客户端必须在不被信任时工作。相反,客户端发送一个访问令牌,从技术上讲是一种bearer令牌,作为访问cookie的代理。本规范描述了一旦浏览器获得了内容资源的访问cookie,客户端如何获得访问令牌,以便在对描述资源进行直接请求时使用。
资源域的服务器将访问令牌视为内容资源访问cookie的代理。当客户端对描述资源提出请求并出示访问令牌时,响应会告诉客户端当浏览器使用访问令牌所代表的访问cookie请求内容资源时会发生什么。这些响应让客户端决定向用户显示什么用户界面和/或内容资源。
1.4 安全性
本规范的目的是支持IIIF资源的访问控制,因此安全是一个核心问题。为了防止滥用,本规范中描述的cookie和bearer令牌需要在存储和传输过程中受到保护,以免泄露。实现推荐使用HTTPS进行所有通信。此外,所有与访问控制资源交互的IIIF客户端也推荐在通过HTTPS提供的页面运行。本规范中对HTTP的所有引用都应假定为使用HTTPS来阅读。
本规范通过将访问令牌提供给客户端应用程序的脚本来保护内容资源(如图像),该令牌用于请求描述资源。获取访问令牌对恶意客户端来说没有意义,因为访问cookie(客户端看不到)是内容资源所接受的唯一凭证,而描述资源本身没有价值。然而,本规范中引入的交互方式将在未来的版本中扩展到对IIIF资源的写入操作,例如在注释服务器中创建注释,或修改清单中的结构元素。对于这些类型的操作,访问令牌就是凭证,下面介绍的流程可能需要一个或多个额外的步骤来建立客户端和服务器之间的信任。不过,预计这些变化将向后兼容1.0版本。
关于安全考虑的进一步讨论可以在实施说明中找到。
2. 认证服务
认证服务遵循 IIIF 链接到外部服务说明中描述的方式,并在一个或多个服务块中被受保护资源的描述所引用。有一个用于验证用户的首要登录服务配置文件,它有嵌套在其描述中的相关服务。相关服务包括一个强制性的访问令牌服务和一个可选的注销服务。
2.1 访问Cookie服务
客户端使用这个服务来获得一个cookie,这个cookie将在与图像等内容交互时使用,并与访问令牌服务交互。在必须为用户渲染的用户界面中,有几种不同的交互方式,客户端将在其中使用该服务,该界面则由一个配置文件URI指示。客户端从受保护资源的描述中的一个服务块中获得访问cookie服务的链接。
访问cookie服务的目的是在用户与内容服务器的交互过程中设置一个cookie,这样当客户端随后向内容服务器发出图像请求时,请求就会成功。客户端对登录服务所发生的事情一无所知,它不能看到在用户与登录服务交互期间为内容域设置的任何cookies。浏览器可能会被重定向一次或多次,但这对客户端应用程序来说是不可见的。打开的标签页中的最终响应推荐包含能够关闭标签页的JavaScript,以便触发工作流程的下一步。
2.1.1 服务描述
有四种交互方式,客户端可以通过这些方式获得访问cookie,每一种方式都由一个配置文件URI识别。这些方式将在以下章节中详细描述。
方式 | 配置文件URI | 说明 |
---|---|---|
Login | http://iiif.io/api/auth/1/login | 用户将被要求使用一个单独的窗口登录,其用户界面由外部认证系统提供。 |
Clickthrough | http://iiif.io/api/auth/1/clickthrough | 用户需要在客户端内点击一个按钮以使用服务描述中提供的内容。 |
Kiosk | http://iiif.io/api/auth/1/kiosk | 用户将不需要与认证系统进行交互,客户端预计将自动使用访问cookie服务。 |
External | http://iiif.io/api/auth/1/external | 用户被认为已经获得了相应的cookie,访问cookie服务将完全不被使用。 |
服务描述包含在描述资源中,具有以下属性:
属性 | 是否必须包含? | 说明 |
---|---|---|
@context | 必须 | 描述IIIF认证API的上下文文件。该属性的值必须是http://iiif.io/api/auth/1/context.json。 |
@id | 依情况而定 | 在Login、Clickthrough或Kiosk方式中,它是必须的,在这些模式中,客户端打开URI以获得访问cookie。在External方式中,它是可选的,因为用户被认为已经通过其他方式获得了cookie,任何提供的值都会被忽略。 |
profile | 必须 | 服务的配置文件必须是上表中的配置文件URI之一。 |
label | 必须 | 当需要多种服务时,用于启动加载认证服务的向用户显示的文本。该值必须包括用户正在进行认证的域或机构。 |
confirmLabel | 推荐 | 在触发打开访问cookie服务的按钮或元素上向用户显示的文本。如果不存在,客户端应在需要时提供适合交互方式的文本。 |
header | 推荐 | 一个简短的文本,如果存在,必须作为描述的header显示给用户,如果没有给出描述,则单独显示。 |
description | 推荐 | 如果存在,在打开访问cookie服务之前必须向用户显示的文本。 |
failureHeader | 可选 | 一个简短的文本,如果存在,在未能收到令牌或使用令牌引起了错误后,可以选择作为显示给用户的header。 |
failureDescription | 可选 | 如果存在,在未能收到令牌或使用令牌引起了错误后,可以选择作为显示给用户的文本。 |
service | 必须 | 对访问令牌和其他相关服务的引用,如下所述。 |
2.1.2 与访问Cookie服务的交互
客户端必须将以下请求参数附加到所有对访问cookie服务URI的请求中,无论交互方式如何,并在新窗口或标签页中打开该URI。
参数 | 说明 |
---|---|
origin | 一个包含窗口中页面来源的字符串,由协议、主机名和可选的端口号组成,如postMessage API规范中所述。 |
例如,给定一个访问cookie服务URI为https://authentication.example.org/login,一个由页面https://client.example.com/viewer/index.html 实例化的客户端将向其发出请求。
https://authentication.example.org/login?origin=https://client.example.com/ |
---|
服务器可以选择使用这一信息来验证在随后对访问令牌服务的请求中提供的来源,例如,将其编码在返回的cookie中。
2.1.3 Login交互方式
为了让客户端提示用户登录,它必须显示内容提供者用户界面的一部分。对于Login交互方式,@id属性的值是该用户界面的URI。
该交互方式需要以下步骤:
- 在打开提供者的认证界面之前,如果header和/或description属性存在,客户端推荐向用户显示这些属性的值。这些属性将描述当他们点击带有confirmLabel的元素时将要发生什么。
- 当confirmLabel元素被激活时,客户端必须从@id中打开URI,并添加来源查询参数。这必须在一个新的窗口或标签页中进行,以帮助防止欺骗性攻击。浏览器的安全规则使客户端无法知道新标签页中发生了什么,因此客户端只能等待并检测已打开的标签页的关闭情况。
- 在打开的标签页被关闭后,客户必须进一步使用相关的访问令牌服务,如下所述。
有了带外(out-of-band)知识,授权的非用户驱动的客户端可以选择使用POST请求将预先认证的用户信息发送给服务。由于所需的信息取决于授权逻辑,该API没有指定细节。
登录交互模式的服务描述示例:
{
// ...
"service" : {
"@context": "http://iiif.io/api/auth/1/context.json",
"@id": "https://authentication.example.org/login",
"profile": "http://iiif.io/api/auth/1/login",
"label": "Login to Example Institution",
"header": "Please Log In",
"description": "Example Institution requires that you log in with your example account to view this content.",
"confirmLabel": "Login",
"failureHeader": "Authentication Failed",
"failureDescription": "<a href=\"http://example.org/policy\">Access Policy</a>",
"service": [
// Access token and Logout services ...
]
}
}
2.1.4 Clickthrough交互方式
对于Clickthrough交互方式,@id属性的值是一个服务的URI,该服务必须设置一个访问cookie并在没有用户交互的情况下立即关闭其窗口或标签。该交互有以下步骤:
- 在打开服务之前,如果header和/或description属性存在,客户端必须向用户显示这些属性的值。这些属性将描述点击带有confirmLabel的元素时所隐含的协议。
- 当confirmLabel元素被激活时,客户端必须从@id中打开URI,并添加开源请求参数。这应该在一个新的窗口或标签页中完成。浏览器的安全规则使客户端无法知道新标签页中发生了什么,因此,客户端只能等待并检测打开的窗口或标签页或iframe的关闭情况。
- 在打开的标签被关闭后,客户必须进一步使用相关的访问令牌服务,如下所述。
非用户驱动的客户端禁止使用具有Clickthrough交互方式的访问cookie服务,而应停止。
Clickthrough交互方式的服务描述示例:
{
// ...
"service" : {
"@context": "http://iiif.io/api/auth/1/context.json",
"@id": "https://authentication.example.org/clickthrough",
"profile": "http://iiif.io/api/auth/1/clickthrough",
"label": "Terms of Use for Example Institution",
"header": "Restricted Material with Terms of Use",
"description": "<span>... terms of use ... </span>",
"confirmLabel": "I Agree",
"failureHeader": "Terms of Use Not Accepted",
"failureDescription": "You must accept the terms of use to see the content.",
"service": {
// Access token service ...
}
}
}
2.1.5 Kiosk交互方式
对于Kiosk交互方式,@id属性的值是一个服务的URI,该服务必须设置一个访问cookie并在没有用户交互的情况下立即关闭其窗口或标签。该交互需要以下步骤:
- 在打开访问cookie服务的URI之前没有用户交互,因此如果存在任何label、header、description和confirmLabel属性,它们都会被忽略。
- 客户端必须立即打开来自@id的URI,并添加来源请求参数。推荐在一个新的窗口或标签页中完成。浏览器的安全规则使客户端无法知道新标签页中发生了什么,因此客户端只能等待和检测打开的窗口、标签页或框架的关闭。
- 在打开的标签页被关闭后,客户必须进一步使用相关的访问令牌服务,如下所述。
非用户驱动的客户端只需从@id访问URI以获得访问cookie,然后使用相关的访问令牌服务,如下所述。
Kiosk交互方式的一个服务描述示例:
{
// ...
"service" : {
"@context": "http://iiif.io/api/auth/1/context.json",
"@id": "https://authentication.example.org/cookiebaker",
"profile": "http://iiif.io/api/auth/1/kiosk",
"label": "Internal cookie granting service",
"failureHeader": "Ooops!",
"failureDescription": "Call Bob at ext. 1234 to reboot the cookie server",
"service": {
// Access token service ...
}
}
}
2.1.6 External交互方式
对于External交互方式,用户需要通过带外的方式获得访问cookie。如果访问cookie不存在,用户将收到失败信息。该交互需要以下步骤:
- 在打开访问令牌服务的URI之前没有用户交动,因此如果存在任何label、header、description和confirmLabel属性,它们都会被忽略。
- 没有访问cookie服务。在@id属性中指定的任何URI必须被忽略。
- 客户端必须立即使用相关的访问令牌服务,如下文所述。
非用户驱动的客户端只需使用相关的访问令牌服务和先前获得的访问cookie,如下所述。
外部交互模式的一个服务描述示例:
{
// ...
"service" : {
"@context": "http://iiif.io/api/auth/1/context.json",
"profile": "http://iiif.io/api/auth/1/external",
"label": "External Authentication Required",
"failureHeader": "Restricted Material",
"failureDescription": "This material is not viewable without prior agreement",
"service": {
// Access token service ...
}
}
}
2.2 访问令牌服务
客户端使用该服务获得一个访问令牌,然后在请求描述资源时使用。从用户与相应的访问cookie服务的交互中可以获得内容域的cookie,对访问令牌服务的请求必须包括获得的内容域的任何cookie,以便服务器能够发放访问令牌。
2.2.1 服务描述
访问cookie服务描述必须包括遵循以下模板的访问令牌服务描述:
{
// Access Cookie Service
"service" : {
"@context": "http://iiif.io/api/auth/1/context.json",
"@id": "https://authentication.example.org/login",
"profile": "http://iiif.io/api/auth/1/login",
"label": "Login to Example Institution",
// Access Token Service
"service": [
{
"@id": "https://authentication.example.org/token",
"profile": "http://iiif.io/api/auth/1/token"
}
]
}
}
访问令牌服务的@id属性必须存在,其值必须是客户端可以获得访问令牌的URI。profile属性必须存在,其值必须是http://iiif.io/api/auth/1/token,以便将其与其他服务区分开来。无需重复包含在封闭的访问cookie服务描述中的@context属性,并且该服务没有其他属性。
2.2.2 JSON访问令牌响应
如果请求具有一个有效的cookie,并且服务器识别为是由访问cookie服务发出的,那么访问令牌服务响应必须包括一个具有以下结构的JSON(非JSON-LD)对象。
{
"accessToken": "TOKEN_HERE",
"expiresIn": 3600
}
accessToken属性是必须具备的,其值是未来请求中要传回的访问令牌。expiresIn属性是可选的,如果存在,其值是访问令牌失效前的秒数。
一旦获得访问令牌,在今后所有对描述资源的请求中,必须通过添加Authorization请求header将访问令牌传回给服务器,其值为Bearer,后面是空格和访问令牌,如:
Authorization: Bearer TOKEN_HERE
所有来自同一域和子域的资源请求中推荐添加这个authorization header,这些请求都有对服务的引用,无论与哪个API进行交互。它被禁止发送到其他域。
2.2.3 与非浏览器客户端应用程序的交互
最简单的访问令牌请求来自一个可以跨域发送cookies的非浏览器客户端,其中CORS限制并不适用。一个例子URL:
https://authentication.example.org/token
将发出HTTP请求:
GET /token HTTP/1.1
Cookie:
其响应是媒体类型为application/json的JSON访问令牌对象:
{
"accessToken": "TOKEN_HERE",
"expiresIn": 3600
}
2.3.4 与基于浏览器的客户端应用程序的交互
如果客户端是一个运行在web浏览器中的JavaScript应用程序,它需要直接请求访问令牌并存储结果。客户端不能使用XMLHttpRequest,因为它不能在跨域请求中包括访问cookie。相反,客户端必须在一个框架中使用iframe元素打开访问令牌服务,并准备好接收由该框架中的脚本使用postMessage API发送的消息。要触发这种行为,客户端必须在访问令牌服务URI上添加以下请求参数,并在框架中打开这个新URI。
参数 | 说明 |
---|---|
messageId | 一个字符串,既提示服务器用网页而不是JSON进行响应,又允许客户端将访问令牌服务请求与收到的消息进行匹配。如果客户端不需要与多个令牌服务进行交互,它可以使用一个假的参数值,例如,messageId=1。 |
origin | 一个包含窗口中页面来源的字符串,由协议、主机名和可选的端口号组成,如postMessage API规范中所述。 |
例如,一个由页面实例化的客户端在https://client.example.com/viewer/index.html,将请求:
https://authentication.example.org/token?messageId=1&origin=https://client.example.com/
当服务器收到带有messageId参数的访问令牌服务请求时,它必须以一个HTML网页而不是原始JSON来响应。该网页必须包含使用postMessage API向开放页面发送消息的脚本。消息主体是JSON访问令牌对象,提供的messageId的值是一个额外的属性,如下一部分的例子所示。
即使用户已经通过了认证,服务器也可以选择将来源信息用于进一步的授权逻辑。例如,服务器可能只信任特定的域中的某些操作,如创建或删除资源,而不是简单地读取资源。如果客户端发送了一个不正确的值,它将不会收到发送的响应,因为postMessage API将不会触发该事件。postMessage()函数调用的targetOrigin参数必须是请求中提供的origin。
该框架不推荐显示给用户。它是一种跨域信息传递的机制。客户端必须注册一个事件监听器来接收框架中的令牌服务页面将发送的消息。客户端可以重复使用相同的监听器和框架来多次调用访问令牌服务,也可以为每次调用创建新的监听器和框架。
具体的实施方式会有所不同,但必须包括相当于以下JavaScript语句的功能。
客户端必须首先注册一个事件监听器来接收跨域消息:
window.addEventListener("message", receive_message);
function receive_message(event) {
data = event.data;
var token, error;
if (data.hasOwnProperty('accessToken')) {
token = data.accessToken;
} else {
// handle error condition
}
// ...
}
然后,它可以在一个框架中打开访问令牌服务:
document.getElementById('messageFrame').src =
'https://authentication.example.org/token?messageId=1234&origin=https://client.example.com/';
然后,服务器的响应将是一个媒体类型为text/html的网页,可以向注册的监听器发送信息:
<html>
<body>
<script>
window.parent.postMessage(
{
"messageId": "1234",
"accessToken": "TOKEN_HERE",
"expiresIn": 3600
},
'https://client.example.com/'
);
</script>
</body>
</html>
2.3.5 Using the Access Token
访问令牌会在随后对描述资源的所有请求中发送。例如,对图像API中的图像信息的请求会是这样的:
GET /iiif/identifier/info.json HTTP/1.1
Authorization: Bearer TOKEN_HERE
2.3.6 访问令牌错误条件
来自访问令牌服务的响应可能是一个错误。该错误必须以JSON格式提供,并使用以下模板。对于使用postMessage API的基于浏览器的客户端,必须通过JavaScript将错误对象发送给客户端,与发送访问令牌的方式相同。对于直接请求,响应体是原始JSON。
{
"error": "ERROR_TYPE_HERE",
"description": "..."
}
错误属性的值必须是下表中的类型之一:
类型 | 说明 |
---|---|
invalidRequest | 该服务无法处理请求正文中发送的信息。 |
missingCredentials | 该请求不具备所需的资格证书。 |
invalidCredentials | 该请求的凭证对该服务无效。 |
invalidOrigin | 该请求来自与访问cookie服务请求中指定的不同来源,或服务器因其他原因拒绝的来源。 |
unavailable | 除上述原因外,该请求无法得到满足,如预定的维护。 |
description属性是可选的,可以给出关于错误的额外的人类可读信息。
当直接返回JSON时,服务必须为响应使用适当的HTTP状态码来描述错误(如400、401或503)。postMessage网页响应必须使用200HTTP状态码,以确保客户端正确接收主体。
2.3 注销服务
在使用Login交互方式的情况下,客户端将需要知道用户是否以及在哪里可以注销。例如,用户可能希望在公共终端上关闭他们的会话,或者用不同的账户再次登录。
2.3.1 服务说明
如果认证系统支持用户主动注销,推荐使用一个与访问cookie服务相关联的注销服务,遵循以下模板:
{
// ...
"service" : {
"@context": "http://iiif.io/api/auth/1/context.json",
"@id": "https://authentication.example.org/login",
"profile": "http://iiif.io/api/auth/1/login",
"label": "Login to Example Institution",
"service" : [
{
"@id": "https://authentication.example.org/token",
"profile": "http://iiif.io/api/auth/1/token"
},
{
"@id": "https://authentication.example.org/logout",
"profile": "http://iiif.io/api/auth/1/logout",
"label": "Logout from Example Institution"
}
]
}
}
profile属性的值必须是http://iiif.io/api/auth/1/logout。
2.3.2 交互
客户端推荐在一个带有URL栏的单独标签页或窗口中展示对服务URI的HTTP GET请求的结果。同时,客户端应该丢弃它从相应服务收到的任何访问令牌。服务器应该在发出这个请求时重置用户的登录状态并删除访问cookie。
2.4 实例描述 带有认证服务的资源
下面的例子是一个具有所有认证服务的示例图像的完整图像信息响应。
{
"@context" : "http://iiif.io/api/image/2/context.json",
"@id" : "https://www.example.org/images/image1",
"protocol" : "http://iiif.io/api/image",
"width" : 600,
"height" : 400,
"sizes" : [
{"width" : 150, "height" : 100},
{"width" : 600, "height" : 400}
],
"profile" : [
"http://iiif.io/api/image/2/level2.json",
{
"formats" : [ "gif", "pdf" ],
"qualities" : [ "color", "gray" ],
"supports" : [
"canonicalLinkHeader", "rotationArbitrary"
]
}
],
"service" : {
"@context": "http://iiif.io/api/auth/1/context.json",
"@id": "https://authentication.example.org/login",
"profile": "http://iiif.io/api/auth/1/login",
"label": "Login to Example Institution",
"service" : [
{
"@id": "https://authentication.example.org/token",
"profile": "http://iiif.io/api/auth/1/token"
},
{
"@id": "https://authentication.example.org/logout",
"profile": "http://iiif.io/api/auth/1/logout",
"label": "Logout from Example Institution"
}
]
}
}
3. 与访问控制资源的交互
本节描述了客户端在与内容资源和描述资源交互时如何使用上述服务。
这些交互依赖于描述资源的请求在不同情况下返回的HTTP状态码200、302和401。在302以外的情况下,响应的主体必须是一个有效的描述资源,因为客户端需要看到认证服务的描述,以便遵循适当的工作流程。任何带有302状态代码的响应都不会被通过XMLHttpRequest API交互的基于浏览器的客户脚本看到。报告的响应将是链中的最后一个,因此重定向响应的主体不需要是描述资源的表示。
3.1 全有或全无的访问
如果服务器不支持对内容资源的分级访问,并且用户没有被授权访问它,那么服务器必须为相应的描述资源返回一个带有401(未授权)HTTP状态码的响应。
如果用户被授权访问描述资源,客户端可以认为对描述内容资源的请求也将被授权。对内容资源的请求依靠访问cookie来传达授权状态。
3.2 分级访问
如果一个服务器支持分级访问,那么它必须为每个描述资源和其相应的内容资源使用不同的标识符。例如,在每个级别的不同URI上必须有不同的图像信息文件(/info.json)。当提及具有多级访问权的描述资源时,系统推荐使用适当的授权用户应该看到的版本的标识符。例如,当从清单中引用图像服务时,通常会引用最高质量的图像版本,而不是降级的版本。
当一个描述资源被请求,而用户没有被授权访问它,并且有更低级别的资源可用时,服务器必须发出302(Found)HTTP状态响应,以重定向到低级别的描述资源。
当没有较低级别并且用户没有被授权访问当前的描述资源时,服务器必须发出401(未授权)响应。客户端推荐提出描述资源中包含的登录和/或点击服务的信息,以允许用户尝试进行验证。
4. 从浏览器客户端的角度看工作流程
基于浏览器的客户端将执行以下工作流程,以访问受控资源:
- 客户端请求描述资源并检查响应的状态代码。
- 如果响应是200,
- 客户端检查响应中的@id属性是否与请求的URI相同。
- 如果是,那么客户端可以继续请求内容资源。
- 如果URI不同,那么该资源就来自与请求的资源不同的级别。200状态意味着该资源可以被使用,因此客户端可以呈现该资源。同时,客户端检查收到的JSON中的认证服务。
- 如果响应是401,
- 客户端没有对内容资源的访问权,因此,客户端在收到的JSON中检查认证服务。
- 如果响应既不是200也不是401,客户端必须处理其他HTTP状态代码
- 当客户端检查认证服务时,它首先检查认证服务:
- 首先,它寻找一个External交互方式,因为这不需要任何用户交互。如果存在,它会打开访问令牌服务,看是否已经获得了Cookie。
- 如果没有,它就检查Kiosk交互方式,因为它不涉及用户交互。如果存在,它会在一个单独的窗口中打开访问Cookie服务。
- 如果没有,它就检查是否有 Clickthrough交互方式。如果存在,它将显示服务的描述和一个确认按钮,提示用户点击通过。一旦用户点击了确认,它就会在一个单独的窗口中打开访问Cookie服务。
- 如果没有,它会显示任何可用的Login交互方式,并提示用户用其中一个登录。当用户选择要登录的域,而该域需要访问Cookie服务的角色时,它会在一个单独的窗口中打开该域的用户界面。
- 当访问Cookie服务的窗口自动或由用户关闭时,客户端会打开访问令牌服务。
在请求访问令牌服务后,如果客户端收到令牌,它将再次尝试用新获得的凭证读取描述资源。
- 如果客户端收到一个错误,它将返回去寻找进一步的认证服务来进行交互。
如果没有进一步的认证服务,那么用户就没有与任何内容资源版本交互的凭证,客户端就不能显示任何东西。
请注意,服务器的实现涉及提供302状态响应,如果用户尚未被授权查看资源,则将客户端从请求的级别重定向到另一个级别。基于浏览器的客户端没有看到这些响应,因此测试资源的标识符是否与请求的资源相同,而不是测试HTTP状态代码。
附录
A. 实施说明
实施者的指导是在一个单独的实施说明文件中提供的。这些说明涵盖了与在基于浏览器的JavaScript应用程序中实施本规范有关的许多细节,以及额外的安全考虑。
B.版本管理
从0.9.0版本开始,本规范遵循语义版本控制。关于如何实现的细节,请参见API的版本控制。
C.致谢
本文件的制作得到了安德鲁-W-梅隆基金会的慷慨支持。
非常感谢IIIF社区成员的持续参与、创新想法和反馈。
D.变更日志
时间 | 说明 |
---|---|
2017-01-19 | Version 1.0 (Alchemical Key) |
2016-10-05 | Version 0.9.4 (Incrementing Integer) 添加了安全注释 |
2016-08-22 | Version 0.9.3 (Wasabi KitKat) 独立的配置文件,删除客户身份服务,添加查询参数 |
(unreleased) | Version 0.9.2 (unnamed) 使用postMessage 代替 JSONP |
2015-10-30 | Version 0.9.1 (Table Flip) 加入遗漏的 @context, clarifications属性 |
2015-07-28 | Version 0.9.0 (unnamed) 草案 |