重要
本文整体介绍如何在高信任授权系统(而非 ACS 系统)中使用访问令牌。 有关在 ACS 系统中使用安全令牌的信息,请参阅在提供程序托管的低信任 SharePoint 加载项中处理安全令牌。
对于使用高信任授权系统获得 SharePoint 访问权限的 SharePoint 加载项,必须在每个创建、读取、更新或删除 (CRUD) 请求中将访问令牌(以 JSON Web 令牌格式)传递到 SharePoint。 SharePoint 验证令牌并提供请求。
本文提供关于代码如何创建和传递访问令牌的信息。
在高信任授权系统中,SharePoint 加载项的远程组件可创建访问令牌。 如果远程组件对服务器端代码使用托管代码,创建令牌的大部分编码工作将在包含在 Visual Studio 的 Office 开发人员工具的 SharePointContext.cs(或 .vb)和 TokenHelper.cs(或 .vb)文件中为你执行。
高信任 SharePoint 加载项客户拥有本地 SharePoint,他们可能不反对将 ASP.NET、IIS 和 Windows Server 用作远程组件的托管堆栈。 应考虑使用此堆栈,因为生成的两个文件将为你节省大量编码和测试工作。
如果远程组件必须使用非 .NET 语言,且远程组件和 SharePoint 场均连接到 Internet,应考虑使用低信任授权系统而非高信任授权系统。 在 Microsoft Azure 访问控制服务 (ACS) 系统中,所有令牌构建均由 ACS 完成,因此也可以为你节省大量劳力。
本文的其余部分主要用于指导开发人员创建带有非 .NET 远程组件的 SharePoint 加载项以及使用高信任授权系统。 本文还提供了关于调试使用高信任系统的基于 .NET 的 SharePoint 加载项的有用信息。
处理访问令牌
注意
在阅读本文时,尤其是有关你的代码必须执行的任务部分,如果你使用的是托管代码,Microsoft Visual Studio 的 Office 开发人员工具会向每个 SharePoint 加载项中添加生成的两个代码文件,即 SharePointContext.cs(或 .vb)和 TokenHelper.cs(或 .vb),这两个文件将为你执行大部分任务。 你的应用程序的令牌处理代码通常仅由对这些文件中类的一些调用组成。
本主题中的详细信息旨在帮助不使用托管代码的开发人员(以及正在对令牌进行故障排除的人员)。 多语言和平台的 OAuth 库的链接位于:OAuth 2.0(滚动到客户端库)。 可以通过在 GitHub中搜索“OAuth 2”和“JSON web token”(不含引号)来查找更多信息。
你的代码需要执行以下任务:
创建访问令牌。 根据远程 Web 应用程序是对 SharePoint 发出仅加载项调用还是用户+加载项调用还是同时发出两种调用,创建此令牌的子任务可能有所不同。 (有关详细信息,请参阅 SharePoint 中的加载项授权策略类型)。
如果加载项发出用户+加载项调用,则创建访问令牌包含以下子任务:
- 创建参与者令牌,用于标识 SharePoint 加载项并通知 SharePoint 将用户身份验证和授权委派给加载项,并使用 Base64 编码对其进行编码。 有关参与者令牌的声明和结构的详细信息,请参阅表 2。 有关对令牌进行编码和签名的详细信息,请参阅对令牌进行编码和签名。
- 使用 X.509 证书中的凭据对参与者令牌进行签名,SharePoint 场管理员已将 SharePoint 配置为信任此证书。
- 将参与者令牌包含在访问令牌中。
- 将其他必需的声明添加到访问令牌。 有关令牌的声明和结构的详细信息,请参阅表 1。
如果加载项发出仅加载项调用,则你的代码仅需执行前两项子任务。 参与者令牌充当访问令牌。
如果外接程序发出一些用户+外接程序调用和一些仅外接程序调用,它必须为仅外接程序调用创建一个简单的参与者令牌,为用户+外接程序调用创建一个较大的嵌套式访问令牌。 同一个访问令牌不能同时用于两者。
在对 SharePoint 的每个 HTTP 请求中包含访问令牌。 令牌添加为请求的 Authorization 标头。 标头的值为“Bearer”,后跟空格,然后是 Base 64 编码的基本访问令牌。
(可选) 缓存访问令牌 ,以便在后续请求中重复使用。
这些任务必须通过服务器端代码执行。 如果使用托管代码,其中一些任务的示例代码位于 Microsoft Office Developer Tools for Visual Studio 生成的 SharePointContext.cs (或 .vb) 和 TokenHelper.cs (或 .vb) 文件中。
缓存访问令牌
创建令牌后,它可以在对 SharePoint 的后续调用中重复使用,直至其过期。 根据远程组件的体系结构和托管平台,有多种方法可以在服务器上缓存访问令牌。
- 在会话状态中
- 在应用程序状态中
- 在 Windows Server AppFabric 缓存中。
- 在数据库中
- 在 memcached 系统中
如果缓存存储由不同的用户会话共享(例如应用程序缓存),则务必使用对会话唯一的缓存密钥。
如果缓存由多个应用程序共享,则代码还必须为该变量对缓存密钥进行相对化处理。 你的加载项还可能访问不同的 SharePoint 场。 需要为每个场提供不同的访问令牌,因此在这种情况下,你的缓存密钥需要针对场进行相对化处理。
总而言之,你可能需要基于一个或多个用户 ID、应用程序 ID 和 SharePoint 域或领域的缓存密钥。 考虑使用与利用低信任授权系统的 SharePoint 加载项所使用的类似的缓存密钥系统。 有关详细信息,请参阅了解缓存密钥。
从根本上来说,需要将这三个 ID 中的一个或多个串联起来(可选择对结果执行哈希以形成一个较短的字符串)作为缓存密钥。
处理过期的访问令牌
访问令牌具有过期时间,你的代码可设置为所需的任何值。 如果加载项为每个请求构造新的访问令牌,则每个令牌的有效期仅需足够它通过 SharePoint 验证,甚至连多几秒都不需要,除非客户的 LAN 经常堵塞。 以后可以将期限设置为数年,但即使在为其设计高信任加载项的“所有本地部署”方案中,访问令牌也有被窃取的危险。 因此,应考虑将过期时间设置为几小时以内。 (如果使用托管代码,TokenHelper.cs [或 .vb] 文件中的示例令牌创建代码会将过期时间设置为 12 小时。)
如果用户与你的 SharePoint 加载项的会话持续时间超过缓存访问令牌的有效期,则令牌过期后对 SharePoint 的第一个请求将导致 401 未经授权错误。 代码必须处理此响应。 或者,代码也可以在使用之前测试访问令牌的过期时间。 你的代码应该通过创建新的访问令牌并重复失败的请求 ,来对过期的访问令牌做出响应。
访问令牌的结构
下面是高信任 SharePoint 加载项生成的访问令牌示例;具体地说,该令牌由 TokenHelper.cs(或 .vb)文件中的示例代码生成,该文件是 Visual Studio 的 Office 开发人员工具创建的 SharePoint 加载项项目模板的一部分。 该令牌已进行解码,并已添加空格以提高可读性。 高信任系统中使用的访问令牌符合 MS SPS2SAUTH:OAuth 2.0 身份验证协议:SharePoint 配置文件(也称为服务器间协议或 S2S 协议)。 该信息可帮助使用托管代码的开发人员调试高信任 SharePoint 加载项,并为使用其他语言的开发人员提供关于构建令牌的指导。
如果加载项使用用户+加载项策略调用 SharePoint,将生成此访问令牌。 如果加载项使用仅加载项策略并对 SharePoint 进行仅加载项调用,参与者令牌(用户+加载项访问令牌中的子令牌,如下所述)将成为访问令牌(没有父令牌)。
注意
请注意,你的代码创建的高信任访问令牌与使用低信任授权系统时 Azure ACS 创建的令牌有所不同:
- 标头中的
alg
声明为“none”,因为高信任加载项发出的用户+加载项调用中的访问令牌尚未签署。 - 在本示例中,
aud
值中的加载项 URL 为本地服务器,这对高信任系统来说很正常。 - 不提供
identityprovider
声明,但提供与低信任授权系统中所用identityprovider
声明访问令牌相同类型的值的nii
(名称标识颁发者)。 (有关当标识提供程序基于 SAML 时此值的信息,请参阅 Steve Peschka 的博客文章SharePoint 加载项中的安全性 - 第 8 部分和在 SharePoint 2013 中将 SharePoint 加载项与 SAML 和 FBA 网站一起使用。 - 不提供
actor
声明,但提供包含有效期为 12 小时的 Base 64 编码的内部令牌的actortoken
声明。
标头具有两个属性。 “typ”是令牌的类型。 远程 Web 应用程序中的代码应始终将此值设置为“JWT”。 “alg”是用于对令牌进行签名的算法。 由于高信任加载项发出的用户+加载项调用中的外部令牌尚未签署,请将该值设置为“none”。 有关高信任访问令牌正文部分中值的信息,请参阅表 1。
{"typ":"JWT", "alg":"none"}
.
{
"aud":"00000003-0000-0ff1-ce00-000000000000/MarketingServer@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2",
"iss":"c3ab8885-458f-4864-8804-1608145e2ac4@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2",
"nbf":"1403212820",
"exp":"1403256020",
"nameid":"s-1-5-21-2127521184-1604012920-1887927527-2963467",
"nii":"urn:office:idp:activedirectory",
"actortoken":"6sMZhbw … [remainder of long base 64 string omitted] … "
}
下表说明了你的代码应该将哪些属性包含在访问令牌中,以及应该为这些属性设置什么值。 如果使用托管代码,SharePointContext.cs(或 .vb)和 TokenHelper.cs(或 .vb)文件将为你创建令牌。 例如,你的令牌向 SharePointContext.CreateUserClientContextForSPHost 方法发出单个调用。 该方法又反过来调用 TokenHelper 类中的方法,这些方法可构建 SharePointContext.CreateUserClientContextForSPHost 返回的 SharePoint 客户端上下文对象发出的每个 SharePoint 调用中包含的访问令牌。
表 1:已发放应用的访问令牌声明
声明 | 说明 | 示例访问令牌中相应的值 |
---|---|---|
aud |
“audience”的简写,表示令牌适用的主体。 格式为受众主体 ID/完全限定的 SharePoint 域@SharePoint 领域。 SharePoint 加载项的访问群体主体始终为 00000003-0000-0ff1-ce00-000000000000 。由于高信任 SharePoint 加载项通常用于全本地方案,完全限定的 SharePoint 域名通常只是服务器名称。 SharePoint 领域是访问令牌用于访问的本地 SharePoint 场的 GUID, (或租户的 GUID(如果场已针对租赁) 配置)。 在 SharePoint 服务器上运行 PowerShell Get-SPAuthenticationRealm cmdlet,查找 SharePoint 领域,然后直接在代码中使用该域或将其存储在代码可读取的配置文件中,如 web.config 文件的 app.Settings 部分。 或者,你的代码可以在运行时通过向 SharePoint 发送身份验证质询动态发现 SharePoint 领域。 有关如何在托管代码中如何执行此操作的示例,请参阅 TokenHelper.cs(或 .vb)文件中的 GetRealmFromTargetUrl 方法。 |
00000003-0000-0ff1-ce00-000000000000/MarketingSharePointServer@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2 |
iss |
“issuer”的简写。 它表示创建了令牌的主体。 格式为颁发者 GUID@SharePoint 领域 GUID。 在高信任系统中,加载项本身就是颁发者,因此 SharePoint 加载项的客户端 ID 通常用作颁发者 GUID。 颁发者 ID 中的所有字母都必须为小写形式。 |
c3ab8885-458f-4864-8804-1608145e2ac4@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2 |
nbf |
“not before”的简写。 它表示令牌生效的时间,自 1970 年 1 月 1 日午夜起计算的秒数。 你的代码应将其设置为令牌创建的时刻。 | 1403212820 |
exp |
“expiration”的简写。 它表示自 1970 年 1 月 1 日午夜以来令牌过期的时间(以秒为单位)。 | 1403256020 |
nameid |
为其颁发令牌的用户的唯一标识符。 其格式因标识提供程序而异。 在本示例中,提供程序是 Active Directory。 | s-1-5-21-2127521184-1604012920-1887927527-2963467 |
nii |
“name identifier issuer”的简写。通过 Internet 编号分配机构 (IANA) 注册的标识提供者的唯一名称。 对于高信任 SharePoint 加载项而言,通常为本地标识提供程序,例如本示例中的 Active Directory。 | urn:office:idp:activedirectory |
actortoken |
Base 64 编码的 JWT 令牌,可标识 SharePoint 外接程序并告知 SharePoint 信任外接程序,不论哪个用户在运行此外接程序。 | 请参阅下文。 |
下面显示了解码的 actortoken。 顶部的小型 JavaScript 对象表示法 (JSON) 标头对象包含关于令牌的元数据,包括令牌类型以及用于签署令牌的算法。 标头的 x5t 属性是 X.509 证书发出的摘要,这是令牌的正式颁发者。 要构建此值,你的代码应执行以下操作:
获取证书指纹的字节数组(不是字符串)版本。 这是证书的 SHA-1 摘要。 (在托管代码中,这可以使用 GetCertHash() 方法执行。 需要与你所用语言等效的方法。)
使用 Base 64 URL 编码对字节数组进行编码。
将 x5t 属性的值设置为编码摘要。
表 2 显示了你的代码必须包含在令牌正文中的声明以及要为其设置的值。
{"typ":"JWT","alg":"RS256","x5t":"7MjK99QvkVdwz6UrKldx8AG7ydM"}
.
{
"aud":"00000003-0000-0ff1-ce00-000000000000/MarketingServer@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2",
"iss":"11111111-1111-1111-1111-111111111111@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2",
"nbf":"1403212820",
"exp":"1403256020",
"nameid":"c3ab8885-458f-4864-8804-1608145e2ac4@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2",
"trustedfordelegation":"true"
}
注意
如果高信任加载项使用仅加载项策略并且向 SharePoint 发出仅加载项调用,则此处显示的令牌实际上是访问令牌。 不提供外部令牌。 此外,也不提供 trustedfordelegation
声明,因为用户的权限与仅加载项调用无关。
表 2:已发放证书的 actortoken 声明
声明 | 说明 | 示例访问令牌中相应的值 |
---|---|---|
aud |
与父访问令牌相同。 | 00000003-0000-0ff1-ce00-000000000000/MarketingSharePointServer@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2 |
iss |
这与在父访问令牌中的含义相同,但是颁发者 GUID 不是 Web 应用程序的客户端 ID。 它是证书的 GUID。 尽管应用程序中的代码会构建参与者令牌,但证书被视为参与者令牌的颁发者。 请注意,本示例中的颁发者 GUID 是一个易于记住的 GUID 字符串,当场管理员在 SharePoint 中将 X.509 证书注册为受信任令牌颁发者时,会使用此 GUID。 当同一个证书在场上的所有高信任 SharePoint 外接程序中用作参与者令牌时,这是普遍做法。 管理员也可以选择为每个 SharePoint 加载项使用不同的证书。 在这种情况下,管理员应对证书使用随机生成的不同 GUID。 颁发者 GUID 中的所有字母都必须为小写形式。 |
11111111-1111-1111-1111-111111111111@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2 |
nbf |
与父访问令牌中的含义相同。 | 与父访问令牌的值相同。 |
exp |
与父访问令牌中的含义相同。 | 与父访问令牌的值相同。 |
nameid |
SharePoint 加载项的唯一标识符,因为它是高信任系统中的“参与者”。 格式为 client_ID@SharePoint_realm。 | c3ab8885-458f-4864-8804-1608145e2ac4@52aa6841-b76b-4ed4-a3d7-a259fce1dfa2 |
trustedfordelegation |
一个布尔值,用于指定 SharePoint 是否应该信任 SharePoint 加载项来对用户进行身份验证和授权。 在高信任系统中通常为 true。 请勿将此声明包含在高信任系统的仅加载项调用中。 | true |
对令牌进行编码和签名
当你的代码将所有属性和值添加到标头和正文 JSON 对象后,必须对其进行编码,将其包含在 JSON Web 令牌 (JWT) 中并对其进行签名。 步骤如下。
- 使用 Base 64 URL 编码对标头进行编码。
- 使用 Base 64 URL 编码对有效负载进行编码。
- 将编码的正文串联在编码标头后面,两者之间有一个“.”字符。 这是 JWT。
- 使用 JWT 和证书的私钥创建 SHA256 证书。
- 使用 Base 64 URL 编码对签名进行编码。
- 将签名附加到 JWT 结尾,两者之间有一个“.”字符。
对于在仅加载项调用中使用的参与者令牌,参与者令牌充当访问令牌。 不提供外部令牌。 对于用于用户+加载项调用的访问令牌,上述步骤用于构建参与者令牌,该令牌稍后将作为 actortoken 属性的值插入到访问令牌的正文。 然后使用上面的前三个步骤对完全访问令牌进行编码和构建,但由于未签名,因此其余步骤并不用于外部令牌。
访问令牌疑难解答
免费的 Fiddler 工具可用于捕获你的加载项的远程组件发送到 SharePoint 的 HTTP 请求。 有一个工具的免费扩展,可自动解码请求中的令牌。