处理身份验证

身份验证类型

扩展可以支持一种或多种身份验证。 每种身份验证类型都是不同类型的凭据。 Power Query 中向最终用户显示的身份验证 UI 由扩展支持的凭据类型驱动。

支持的身份验证类型列表定义为扩展数据源 类型 定义的一部分。 每个身份验证值都是具有特定字段的记录。 下表列出了每种类型的预期字段。 除非另有标记,否则所有字段均是必需的。

身份验证类型 领域 Description
匿名 匿名(也称为 Implicit)身份验证类型没有任何字段。
OAuth 开始登录 提供用于启动 OAuth 流的 URL 和状态信息的函数。

转到 “实现 OAuth 流 ”部分。
完成登录 提取与 OAuth 流相关的access_token和其他属性的函数。
刷新 (可选) 从刷新令牌中检索新访问令牌的函数。
Logout (可选) 使用户当前访问令牌失效的函数。
标签 (可选) 一个文本值,用于替代此 AuthenticationKind 的默认标签。
Aad 授权URI text 返回Microsoft Entra ID 授权终结点的值或一元函数(示例: "https://login.microsoftonline.com/common/oauth2/authorize") 。

转到 “Microsoft Entra ID 身份验证 ”部分。
Resource text 返回服务的 Microsoft Entra ID 资源值的返回值或一元函数。
Scope (可选)text 作为身份验证流的一部分返回要请求的范围列表的值或一元函数。 多个范围值用空格分隔。 范围值应为范围名称,没有应用程序 ID URI(示例: Data.Read) 。 当未提供时,请求 user_impersonation 范围。
用户名密码 用户名标签 (可选) 用于替换凭据 UI 上 “用户名 ”文本框的默认标签的文本值。
密码标签 (可选) 一个文本值,用于替换凭据 UI 上 “密码 ”文本框的默认标签。
标签 (可选) 一个文本值,用于替代此 AuthenticationKind 的默认标签。
Windows操作系统 用户名标签 (可选) 用于替换凭据 UI 上 “用户名 ”文本框的默认标签的文本值。
密码标签 (可选) 一个文本值,用于替换凭据 UI 上 “密码 ”文本框的默认标签。
标签 (可选) 一个文本值,用于替代此 AuthenticationKind 的默认标签。
Key KeyLabel (可选) 用于替换凭据 UI 上 API 密钥 文本框的默认标签的文本值。
标签 (可选) 一个文本值,用于替代此 AuthenticationKind 的默认标签。

以下示例显示了支持 OAuth、密钥、Windows、基本(用户名和密码)和匿名凭据的连接器的身份验证记录。

Example:

Authentication = [
    OAuth = [
        StartLogin = StartLogin,
        FinishLogin = FinishLogin,
        Refresh = Refresh,
        Logout = Logout
    ],
    Key = [],
    UsernamePassword = [],
    Windows = [],
    Anonymous = []
]

访问当前凭据

可以使用函数 Extension.CurrentCredential 检索当前凭据。

为扩展性启用的 M 数据源函数会自动继承扩展的凭据范围。 在大多数情况下,您无需显式访问当前凭据,但存在例外,例如:

  • 在自定义标头或查询字符串参数中传入凭据(例如,使用 API 密钥身份验证类型时)。
  • 设置 ODBC 或 ADO.NET 扩展的连接字符串属性。
  • 检查 OAuth 令牌上的自定义属性。
  • 使用凭据作为 OAuth v1 流的一部分。

Extension.CurrentCredential 函数返回记录对象。 包含的字段特定于身份验证类型。 下表包含详细信息。

领域 Description 使用者
认证类型 包含分配给此凭据的身份验证类型的名称(UsernamePassword、OAuth 等)。 全部
用户名 用户名值 UsernamePassword、Windows
密码 密码值。 通常与 UsernamePassword 一起使用,但它也针对密钥进行设置。 Key、用户名密码、Windows
access_token OAuth 访问令牌值。 OAuth
属性 包含给定凭据的其他自定义属性的记录。 通常与 OAuth 一起使用,用于存储认证流程中随 access_token 返回的其他属性(例如 refresh_token)。 OAuth
Key API 密钥值。 请注意,密钥值也可以在“密码”字段中使用。 默认情况下,混合引擎在授权标头中插入此密钥,就好像此值是基本身份验证密码(没有用户名)。 如果此类行为不是所需行为,则必须在选项记录中指定 ManualCredentials = true 选项。 Key
EncryptConnection 一个逻辑值,确定是否需要与数据源建立加密连接。 此值可用于所有身份验证类型,但仅在 数据源 定义中指定 EncryptConnection 时才进行设置。 全部

下面的代码示例访问 API 密钥的当前凭据,并使用它填充自定义标头(x-APIKey)。

Example:

MyConnector.Raw = (_url as text) as binary =>
let
    apiKey = Extension.CurrentCredential()[Key],
    headers = [

        #"x-APIKey" = apiKey,
        Accept = "application/vnd.api+json",
        #"Content-Type" = "application/json"
    ],
    request = Web.Contents(_url, [ Headers = headers, ManualCredentials = true ])
in
    request

实现 OAuth 流程

OAuth 身份验证类型允许扩展为其服务实现自定义逻辑。 为此,扩展提供用于 StartLogin (返回启动 OAuth 流的授权 URI)和 FinishLogin (交换访问令牌的授权代码)的函数。 扩展还可以选择性地实现 Refresh (将刷新令牌兑换为新的访问令牌)和 Logout (使当前的刷新和访问令牌失效)功能。

注释

Power Query 扩展会在客户端计算机上运行的应用程序中进行评估。 数据连接器 不应 在其 OAuth 流中使用机密机密,因为用户可以检查扩展或网络流量来了解机密。 有关提供不依赖于共享机密的流的详细信息,请访问 OAuth 公共客户端 RFC 之代码交换证明密钥(也称为 PKCE)。 可以在 GitHub 上找到此流程的示例实现。

有两组 OAuth 函数签名:包含最少数量的参数的原始签名,以及接受更多参数的高级签名。 大多数 OAuth 流都可以使用原始签名实现。 还可以在实现中混合和匹配签名类型。 函数调用是依据参数的数量及其类型进行匹配的。 不考虑参数名称。

有关更多详细信息,请转到 GitHub 示例

原始 OAuth 签名

StartLogin = (dataSourcePath, state, display) => ...;

FinishLogin = (context, callbackUri, state) => ...;

Refresh = (dataSourcePath, refreshToken) =>  ...;

Logout = (accessToken) => ...;

高级 OAuth 签名

有关高级签名的说明:

  • 所有签名都接受一个 clientApplication 记录值,该值保留供将来使用。
  • 所有签名都接受一个dataSourcePath(在大多数示例中也称为resourceUrl)。
  • Refresh函数接受一个oldCredential参数,该参数是之前由您的FinishLogin函数(或之前对Refresh的调用)返回的record
StartLogin = (clientApplication, dataSourcePath, state, display) => ...;

FinishLogin = (clientApplication, dataSourcePath, context, callbackUri, state) => ...;

Refresh = (clientApplication, dataSourcePath, oldCredential) =>  ...;

Logout = (clientApplication, dataSourcePath, accessToken) => ...;

Microsoft Entra ID 身份验证

身份验证 Aad 类型是用于 Microsoft Entra ID 的 OAuth 的专用版本。 它使用与支持组织帐户身份验证的内置 Power Query 连接器相同的Microsoft Entra ID 客户端。 有关详细信息,请参阅配置 Microsoft Entra 自定义连接器的快速入门指南

注释

如果为 Microsoft Entra ID 实现自己的 OAuth 流,则为租户启用 条件访问 的用户在使用 Power BI 服务刷新时可能会遇到问题。 这不会影响通过网关进行的刷新,但会影响支持从 Power BI 服务刷新的已认证的连接器。 在通过 Power BI 服务配置 Web 凭据时,用户可能会遇到由于连接器使用公共客户端应用程序而引发的问题。 此流生成的访问令牌最终将用于另一台计算机(即 Azure 数据中心中的 Power BI 服务,而不是公司网络上),而不是最初进行身份验证的用户(即在公司网络上配置数据源凭据的用户的计算机)。 内置 Aad 类型通过在 Power BI 服务中配置凭据时使用不同的 Microsoft Entra ID 客户端,从而绕过此问题。 此选项不适用于使用 OAuth 身份验证类型的连接器。

大多数连接器需要为 AuthorizationUriResource 字段提供值。 这两个字段可以是text值,也可以是返回text value的单个参数函数。

AuthorizationUri = "https://login.microsoftonline.com/common/oauth2/authorize"
AuthorizationUri = (dataSourcePath) => FunctionThatDeterminesAadEndpointFromDataSourcePath(dataSourcePath)
Resource = "44445555-eeee-6666-ffff-7777aaaa8888"   // Microsoft Entra ID resource value for your service - Guid or URL
Resource = (dataSourcePath) => FunctionThatDeterminesResourceFromDataSourcePath(dataSourcePath)

使用 基于 URI 的标识符 的连接器不需要提供 Resource 值。 默认情况下,该值等于连接器 URI 参数的根路径。 如果数据源的Microsoft Entra ID 资源不同于域值(例如,它使用 GUID),则需要提供一个 Resource 值。

Aad 身份验证类型示例

在以下情况下,数据源支持全局云环境下的 Microsoft Entra ID,使用通用租户(不支持 Azure B2B)。 请求 .default 范围 将返回一个令牌,其中包含 Power Query 客户端应用程序 ID 的所有以前授权的范围。

Authentication = [
    Aad = [
        AuthorizationUri = "https://login.microsoftonline.com/common/oauth2/authorize",
        Resource = "44445555-eeee-6666-ffff-7777aaaa8888", // Entra Application ID URI or app guid
        Scope = ".default"
    ]
]

在以下情况下,数据源支持基于 OpenID Connect(OIDC)或类似协议的租户发现。 此功能允许连接器根据数据源路径中的一个或多个参数来确定要使用的正确Microsoft Entra ID 终结点。 此动态发现方法允许连接器支持 Azure B2B。


// Implement this function to retrieve or calculate the service URL based on the data source path parameters
GetServiceRootFromDataSourcePath = (dataSourcePath) as text => ...;

GetAuthorizationUrlFromWwwAuthenticate = (url as text) as text =>
    let
        // Sending an unauthenticated request to the service returns
        // a 302 status with WWW-Authenticate header in the response. The value will
        // contain the correct authorization_uri.
        // 
        // Example:
        // Bearer authorization_uri="https://login.microsoftonline.com/{tenant_guid}/oauth2/authorize"
        responseCodes = {302, 401},
        endpointResponse = Web.Contents(url, [
            ManualCredentials = true,
            ManualStatusHandling = responseCodes
        ])
    in
        if (List.Contains(responseCodes, Value.Metadata(endpointResponse)[Response.Status]?)) then
            let
                headers = Record.FieldOrDefault(Value.Metadata(endpointResponse), "Headers", []),
                wwwAuthenticate = Record.FieldOrDefault(headers, "WWW-Authenticate", ""),
                split = Text.Split(Text.Trim(wwwAuthenticate), " "),
                authorizationUri = List.First(List.Select(split, each Text.Contains(_, "authorization_uri=")), null)
            in
                if (authorizationUri <> null) then
                    // Trim and replace the double quotes inserted before the url
                    Text.Replace(Text.Trim(Text.Trim(Text.AfterDelimiter(authorizationUri, "=")), ","), """", "")
                else
                    error Error.Record("DataSource.Error", "Unexpected WWW-Authenticate header format or value during authentication.", [
                        #"WWW-Authenticate" = wwwAuthenticate
                    ])
        else
            error Error.Unexpected("Unexpected response from server during authentication.");

<... snip ...>

Authentication = [
    Aad = [
        AuthorizationUri = (dataSourcePath) =>
            GetAuthorizationUrlFromWwwAuthenticate(
                GetServiceRootFromDataSourcePath(dataSourcePath)
            ),
        Resource = "https://myAadResourceValue.com", // Microsoft Entra ID resource value for your service - Guid or URL
        Scope = ".default"
    ]
]

其他类型的身份验证

有关本文中未涵盖的其他类型的身份验证的信息(如基于 Kerberos 的单一登录),请访问 其他连接器功能 文章了解详细信息。