Manipulando a autenticação

Tipos de autenticação

Uma extensão pode dar suporte a um ou mais tipos de autenticação. Cada tipo de autenticação é um tipo diferente de credencial. A interface do usuário de autenticação exibida aos usuários finais no Power Query é controlada pelo tipo de credencial à qual uma extensão dá suporte.

A lista de tipos de autenticação com suporte é definida como parte da definição de tipo de fonte de dados de uma extensão. Cada valor de autenticação é um registro com campos específicos. A tabela a seguir lista os campos esperados para cada tipo. Todos os campos são necessários, a menos que sejam marcados de outra forma.

Tipo de autenticação Campo Descrição
Implícita O tipo de autenticação implícita (anônima) não tem nenhum campo.
OAuth StartLogin Função que fornece as informações de URL e estado para iniciar um fluxo OAuth.

consulte a seção implementando um Flow de OAuth abaixo.
FinishLogin Função que extrai o access_token e outras propriedades relacionadas ao fluxo do OAuth.
Atualizar (opcional) Função que recupera um novo token de acesso de um token de atualização.
Logout (opcional) Função que invalida o token de acesso atual do usuário.
Rótulo (opcional) Um valor de texto que permite que você substitua o rótulo padrão para este AuthenticationKind.
AAD AuthorizationUri text valor ou função que retorna o ponto de extremidade de autorização do Azure AD (exemplo: "https://login.microsoftonline.com/common/oauth2/authorize" ).

consulte a seção autenticação de Azure Active Directory abaixo.
Recurso text valor ou função que retorna o valor de recurso do Azure AD para seu serviço.
UsernamePassword UsernameLabel (opcional) Um valor de texto para substituir o rótulo padrão da caixa de texto nome de usuário na interface do usuário de credenciais.
PasswordLabel (opcional) Um valor de texto para substituir o rótulo padrão da caixa de texto de senha na interface do usuário de credenciais.
Rótulo (opcional) Um valor de texto que permite que você substitua o rótulo padrão para este AuthenticationKind.
Windows UsernameLabel (opcional) Um valor de texto para substituir o rótulo padrão da caixa de texto nome de usuário na interface do usuário de credenciais.
PasswordLabel (opcional) Um valor de texto para substituir o rótulo padrão da caixa de texto de senha na interface do usuário de credenciais.
Rótulo (opcional) Um valor de texto que permite que você substitua o rótulo padrão para este AuthenticationKind.
Chave Keylabel (opcional) Um valor de texto para substituir o rótulo padrão da caixa de texto de chave de API na interface do usuário de credenciais.
Rótulo (opcional) Um valor de texto que permite que você substitua o rótulo padrão para este AuthenticationKind.

o exemplo a seguir mostra o registro de autenticação para um conector que dá suporte a OAuth, chave, Windows, básico (nome de usuário e senha) e credenciais anônimas.

Exemplo:

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

Acessando as credenciais atuais

As credenciais atuais podem ser recuperadas usando a Extension.CurrentCredential() função.

As funções de fonte de dados que foram habilitadas para extensibilidade herdarão automaticamente o escopo de credenciais da extensão. Na maioria dos casos, você não precisará acessar explicitamente as credenciais atuais, no entanto, há exceções, como:

  • Passando a credencial em um cabeçalho personalizado ou parâmetro de cadeia de caracteres de consulta (como quando você está usando o tipo de autenticação de chave de API)
  • definindo propriedades de cadeia de conexão para ODBC ou extensões de ADO.NET
  • Verificando Propriedades personalizadas em um token OAuth
  • Usando as credenciais como parte de um fluxo OAuth v1

A Extension.CurrentCredential() função retorna um objeto de registro. Os campos que ele contém serão específicos do tipo de autenticação. Confira a tabela a seguir para obter detalhes.

Campo Descrição Usado por
AuthenticationKind Contém o nome do tipo de autenticação atribuído a essa credencial (UsernamePassword, OAuth e assim por diante). Tudo
Nome de Usuário Valor de nome de usuário UsernamePassword, Windows
Senha Valor da senha. Normalmente usado com UsernamePassword, mas também é definido para a chave. Chave, UsernamePassword, Windows
access_token Valor do token de acesso OAuth. OAuth
Propriedades Um registro que contém outras propriedades personalizadas para uma determinada credencial. Normalmente usado com o OAuth para armazenar propriedades adicionais (como o refresh_token) retornado com o access_token durante o fluxo de autenticação. OAuth
Chave O valor da chave de API. Observe que o valor da chave também está disponível no campo senha. Por padrão, o mecanismo de mashup irá inseri-lo em um cabeçalho de autorização como se esse valor fosse uma senha de autenticação básica (sem nome de usuário). Se esse não for o comportamento desejado, você deverá especificar a opção ManualCredentials = true no registro de opções. Chave
EncryptConnection Um valor lógico que determina se uma conexão criptografada deve ser necessária para a fonte de dados. Esse valor está disponível para todos os tipos de autenticação, mas só será definido se EncryptConnection for especificado na definição da fonte de dados . Tudo

O exemplo de código a seguir acessa a credencial atual para uma chave de API e a usa para preencher um cabeçalho personalizado ( x-APIKey ).

Exemplo:

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

Implementando um Flow OAuth

O tipo de autenticação OAuth permite que uma extensão implemente lógica personalizada para seu serviço. Para fazer isso, uma extensão fornecerá funções para (retornando o URI de autorização para iniciar o fluxo OAuth) e (trocando o código de autorização para um StartLogin FinishLogin token de acesso). Opcionalmente, as extensões podem implementar (trocar um token de atualização para um novo token de acesso) e (expirando as funções atuais de atualização e Refresh Logout tokens de acesso) também.

Observação

Power Query extensões são avaliadas em aplicativos em execução em máquinas cliente. Os Conectores de Dados não devem usar segredos confidenciais em seus fluxos OAuth, pois os usuários podem inspecionar a extensão ou o tráfego de rede para aprender o segredo. Consulte a RFC (Chave de prova para código Exchange por clientes públicos OAuth) (também conhecida como PKCE) para obter mais detalhes sobre como fornecer fluxos que não dependem de segredos compartilhados. Uma implementação de exemplo desse fluxo pode ser encontrada em nosso GitHub site.

Há dois conjuntos de assinaturas de função OAuth; a assinatura original que contém um número mínimo de parâmetros e uma assinatura avançada que aceita parâmetros adicionais. A maioria dos fluxos OAuth pode ser implementada usando as assinaturas originais. Você também pode combinar e corresponder tipos de assinatura em sua implementação. As chamadas de função são corresponde com base no número de parâmetros (e seus tipos). Os nomes de parâmetro não são considerados.

Confira o exemplo do Github para obter mais detalhes.

Assinaturas OAuth originais

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

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

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

Logout = (accessToken) => ...;

Assinaturas OAuth avançadas

Observações sobre as assinaturas avançadas:

  • Todas as assinaturas aceitam um clientApplication valor de registro, que é reservado para uso futuro.
  • Todas as assinaturas aceitam dataSourcePath um (também conhecido como resourceUrl na maioria dos exemplos).
  • A Refresh função aceita um parâmetro , que é o anterior retornado pela função oldCredential record FinishLogin (ou chamada anterior para Refresh ).
StartLogin = (clientApplication, dataSourcePath, state, display) => ...;

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

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

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

Autenticação do Azure Active Directory

O Aad tipo de autenticação é uma versão especializada do OAuth para Azure Active Directory. Ele usa o mesmo cliente do Azure AD que os conectores Power Query integrados que suportam a autenticação da Conta da Organização.

Observação

Se a fonte de dados exigir escopos diferentes de ou for incompatível com o uso de , você user_impersonation deverá usar o tipo de user_impersonation OAuth autenticação.

Observação

Se você implementar seu próprio fluxo OAuth para o Azure AD, os usuários que habilitaram o Acesso Condicional para seu locatário poderão encontrar problemas ao atualizar usando o serviço Power BI. Isso não afetará a atualização baseada em gateway, mas afetará um conector certificado que dá suporte à atualização do Power BI serviço. Os usuários podem ter um problema decorrente do conector usando um aplicativo cliente público ao configurar credenciais baseadas na Web por meio do Power BI serviço. O token de acesso gerado por esse fluxo será usado em um computador diferente (ou seja, o serviço Power BI em um data center do Azure, não na rede da empresa) do que aquele usado para autenticar originalmente (ou seja, o computador do usuário que configura as credenciais da fonte de dados na rede da empresa). O tipo interno funciona em torno desse problema usando um cliente diferente do Azure AD ao configurar credenciais no Power BI Aad serviço. Essa opção não estará disponível para conectores que usam o tipo OAuth de autenticação.

A maioria dos conectores precisará fornecer valores para os AuthorizationUri campos Resource e . Ambos os campos podem ser text valores ou uma única função de argumento que retorna um text value .

AuthorizationUri = "https://login.microsoftonline.com/common/oauth2/authorize"
AuthorizationUri = (dataSourcePath) => FunctionThatDeterminesAadEndpointFromDataSourcePath(dataSourcePath)
Resource = "77256ee0-fe79-11ea-adc1-0242ac120002"   // Azure AD resource value for your service - Guid or URL
Resource = (dataSourcePath) => FunctionThatDeterminesResourceFromDataSourcePath(dataSourcePath)

Conectores que usam um identificador baseado em URI não precisam fornecer um Resource valor. Por padrão, o valor será igual ao caminho raiz do parâmetro URI do conector. Se o recurso do Azure AD da fonte de dados for diferente do valor de domínio (por exemplo, ele usa um GUID), um valor precisará Resource ser fornecido.

Exemplos de tipo de autenticação do Aad

Nesse caso, a fonte de dados dá suporte ao Azure AD de nuvem global usando o locatário comum (sem suporte do Azure B2B).

Authentication = [
    Aad = [
        AuthorizationUri = "https://login.microsoftonline.com/common/oauth2/authorize",
        Resource = "77256ee0-fe79-11ea-adc1-0242ac120002" // Azure AD resource value for your service - Guid or URL
    ]
]

Nesse caso, a fonte de dados dá suporte à descoberta de locatários com base Conexão OpenID (OIDC) ou protocolo semelhante. Isso permite que o conector determine o ponto de extremidade correto do Azure AD a ser usado com base em um ou mais parâmetros no caminho da fonte de dados. Essa abordagem de descoberta dinâmica permite que o conector seja compatível com o 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", // Azure AD resource value for your service - Guid or URL
    ]
]

Caminhos da fonte de dados

O mecanismo M identifica uma fonte de dados usando uma combinação de seu Tipo e Caminho. Quando uma fonte de dados é encontrada durante uma avaliação de consulta, o mecanismo M tentará encontrar credenciais correspondentes. Se nenhuma credencial for encontrada, o mecanismo retornará um erro especial que resulta em um prompt de credencial Power Query.

O valor Kind vem da definição tipo de fonte de dados.

O valor path é derivado dos parâmetros necessários da função de fonte de dados. Parâmetros opcionais não são fatorados no identificador de caminho da fonte de dados. Como resultado, todas as funções de fonte de dados associadas a um tipo de fonte de dados devem ter os mesmos parâmetros. Há tratamento especial para funções que têm um único parâmetro do tipo Uri.Type . Consulte a seção abaixo para obter detalhes.

Você pode ver um exemplo de como as credenciais são armazenadas na caixa de diálogo Configurações da fonte de dados Power BI Desktop. Nessa caixa de diálogo, o Tipo é representado por um ícone e o valor caminho é exibido como texto.

DataSourcePaths.

Observação

Se você alterar os parâmetros necessários da função de fonte de dados durante o desenvolvimento, as credenciais armazenadas anteriormente não funcionarão (porque os valores de caminho não corresponderão mais). Você deve excluir quaisquer credenciais armazenadas sempre que alterar os parâmetros de função da fonte de dados. Se as credenciais incompatíveis são encontradas, você pode receber um erro em runtime.

Formato de caminho da fonte de dados

O valor Path de uma fonte de dados é derivado dos parâmetros necessários da função de fonte de dados. Os parâmetros necessários podem ser excluídos do caminho adicionando aos DataSource.Path = false metadados da função (consulte abaixo).

Por padrão, você pode ver o valor real da cadeia de caracteres na caixa de diálogo Configurações da fonte de dados Power BI Desktop e no prompt de credencial. Se a definição tipo de fonte de dados tiver incluído Label um valor, você verá o valor do rótulo.

Por exemplo, a função de fonte de dados no exemplo HelloWorldWithDocs tem a seguinte assinatura:

HelloWorldWithDocs.Contents = (message as text, optional count as number) as table => ...

A função tem um único parâmetro obrigatório ( ) do message tipo e será usada para calcular o caminho da fonte de text dados. O parâmetro opcional ( count ) seria ignorado. O caminho seria exibido

Prompt de credencial:

Datasourcecredentials.

Interface do usuário das configurações da fonte de dados:

DataSourceSettings.

Quando um valor rótulo é definido, o valor do caminho da fonte de dados não seria mostrado:

DataSourceLabel.

Observação

No momento, recomendamos que você não inclua um Rótulo para sua fonte de dados se sua função tiver parâmetros necessários, pois os usuários não poderão distinguir entre as diferentes credenciais inseridas. Esperamos melhorar isso no futuro (ou seja, permitindo que os conectores de dados exibem seus próprios caminhos de fonte de dados personalizados).

Excluindo parâmetros necessários do caminho da fonte de dados

Se você quiser que um parâmetro de função seja necessário, mas não seja incluído como parte do caminho da fonte de dados, poderá adicionar aos metadados da documentação DataSource.Path = false da função. Essa propriedade pode ser adicionada a um ou mais parâmetros para sua função. Esse campo remove o valor do caminho da fonte de dados (o que significa que ele não será mais passado para sua função), portanto, ele só deve ser usado para parâmetros que não são necessários para identificar sua fonte de dados ou distinguir entre as credenciais do TestConnection usuário.

Por exemplo, o conector no exemplo HelloWorldWithDocs exigiria credenciais diferentes para valores message diferentes. Adicionar ao parâmetro o remove do cálculo do caminho da fonte de dados, tornando efetivamente DataSource.Path = false message o conector um "singleton". Todas as chamadas para são tratadas como a mesma fonte de dados e o usuário fornecerá credenciais HelloWorldWithDocs.Contents apenas uma vez.

HelloWorldType = type function (
    message as (type text meta [
        DataSource.Path = false,
        Documentation.FieldCaption = "Message",
        Documentation.FieldDescription = "Text to display",
        Documentation.SampleValues = {"Hello world", "Hola mundo"}
    ]),
    optional count as (type number meta [
        Documentation.FieldCaption = "Count",
        Documentation.FieldDescription = "Number of times to repeat the message",
        Documentation.AllowedValues = { 1, 2, 3 }
    ]))
    as table meta [
        Documentation.Name = "Hello - Name",
        Documentation.LongDescription = "Hello - Long Description",
        Documentation.Examples = {[
            Description = "Returns a table with 'Hello world' repeated 2 times",
            Code = "HelloWorldWithDocs.Contents(""Hello world"", 2)",
            Result = "#table({""Column1""}, {{""Hello world""}, {""Hello world""}})"
        ],[
            Description = "Another example, new message, new count!",
            Code = "HelloWorldWithDocs.Contents(""Goodbye"", 1)",
            Result = "#table({""Column1""}, {{""Goodbye""}})"
        ]}
    ];

Funções com um parâmetro URI

Como as fontes de dados com um identificador baseado em URI são tão comuns, há tratamento especial na interface do usuário Power Query ao lidar com caminhos de fonte de dados baseados em URI. Quando uma fonte de dados baseada em URI é encontrada, a caixa de diálogo de credencial fornece uma lista alternativa permitindo que o usuário selecione o caminho base, em vez do caminho completo (e todos os caminhos entre eles).

DataSourceUrl.

Como é um tipo atribuído em vez de um tipo primitivo na linguagem M, você precisará usar a função Uri.Type Value.ReplaceType para indicar que o parâmetro de texto deve ser tratado como um URI.

shared GithubSample.Contents = Value.ReplaceType(Github.Contents, type function (url as Uri.Type) as any);

Tipos adicionais de autenticação

Para obter informações sobre tipos adicionais de autenticação não abordados neste artigo, como logon único baseado em Kerberos, visite o artigo funcionalidade adicional do conector para saber mais.