Power BI カスタムコネクター開発 : Microsoft Graph コネクターを開発する


前回の記事では M スクリプトからカスタムコネクターを作成する手順を紹介しました。利用したサンプルは匿名認証でしたが、普段使うサービスはおそらく何かしらの認証があるため、今回は OAuth 認証の方法を見ていきます。

尚、OAuth の詳細は説明しないため、気になる人は

などを参照してください。

今回のコードはは こちら のコードをベースにしていますが、説明をシンプルにするため多少変更しています。

Microsoft Graph

Microsoft 365 (旧 Office 365 含む) サービスである Exchange オンラインや SharePoint オンラインまたは Microsoft Teams 等を使っている場合、これらのデータの解析に興味があるでしょう。Microsoft Graph はこれらすべてのサービスにアクセスできるエンドポイントを提供します。

実際取得できるデータをすぐ見たい場合は Graph Explorer を試してください。

カスタムコネクタ用 Azure AD 認証の設定

認証を実施するには、以下 2 つのステップが必要です。

  • Azure AD にアプリケーションを登録する
  • 登録したアプリケーションの情報をカスタムコネクタで利用する

つまり Azure AD に対してアプリケーションを作成する権限が必要ですが、権限がない場合、トライアル環境などを利用してみてください。Microsoft E3/E5 トライアル版であれば検証ができます。

アプリ―ションの登録

1. 管理ポータル より、管理センターにある Azure Active Directory をクリック。

2. Azure Active Directory | アプリの登録 より「新規登録」をクリック。

3. 任意のアプリケーション名を指定。サポートされているアカウントの種類は既定のまま。

4. リダイレクト URI では「パブリック クライアント/ネイティブ」を選択し、https://oauth.powerbi.com/views/oauthredirect.html をアドレスに入力。「登録」をクリック。

5. アプリケーションの画面に遷移したら「API のアクセス許可」より「アクセス許可の追加」をクリック。 

6. コネクターで利用したい権限を選択。ここでは「Microsoft Graph」を選択。

7. Microsoft Graph ユーザーが使う「委任されたアクセス許可」とバックエンドプロセスなどで使う「アプリケーションの許可」がある。ここでは「委任されたアクセス許可」をクリック。

8. サンプルは多くの権限を使っているが、ここでは以下の権限を指定。

  • User.Read (既定で選択されている)
  • Calendars.Read
  • People.Read

9. 「概要」に戻り、アプリケーション ID を保存。

カスタムコネクターの開発

既にあるコードをそのまま使ってもいいのですが、今回は新規にプロジェクトを作っていきます。

プロジェクトの作成

前回の記事 の手順と同様にプロジェクトを作成。名前は MyGraphConnector とした。

DataSource Kind の更新

DataSource.Kind では認証の設定を行います。既定では匿名認証 (Implicit) だけです。また名前は既定でプロジェクトと同じです。

// Data Source Kind description
MyGraphConnector = [
    Authentication = [
        // Key = [],
        // UsernamePassword = [],
        // Windows = [],
        Implicit = []
    ],
    Label = Extension.LoadString("DataSourceLabel")
];

今回は以下のように OAuth 要素だけにします。また OAuth 要素に StartLogin と FinishLogin
FinishLogin を指定しています。OAuth で使えるプロパティは Handling Authentication を参照してください。

MyGraphConnector = [
    Authentication = [
        // Key = [],
        // UsernamePassword = [],
        // Windows = [],
        // Implicit = [],
        OAuth = [
            StartLogin=StartLogin,
            FinishLogin=FinishLogin
        ]
    ],
    Label = Extension.LoadString("DataSourceLabel")
];
  • StartLogin: ユーザーがログインを始めた際に実行される
  • FinishLogin: ログイン後に呼ばれる。OAuth フローではアクセストークンの取得が行われる

この時点では関連する関数がないため、赤線が表示されています。

StartLogin の追加

以下は サンプルコード にある StartLogin を少し変更したものです。任意の場所に張り付けます。

また client_id は先ほど作成したアプリケーション ID を指定します。

client_id = "c83bce1f-cdce-41c2-a07d-9f4c78a074be";

StartLogin = (resourceUrl, state, display) =>
    let
        authorizeUrl = "https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?" & Uri.BuildQueryString([
            client_id = client_id,  
            redirect_uri = "https://oauth.powerbi.com/views/oauthredirect.html",
            state = state,
            scope = "offline_access User.Read Calendars.Read People.Read",
            response_type = "code",
            response_mode = "query",
            login = "login"
        ])
    in
        [
            LoginUri = authorizeUrl,
            CallbackUri = "https://oauth.powerbi.com/views/oauthredirect.html",
            WindowHeight = 720,
            WindowWidth = 1024,
            Context = null
        ];

開発者の方は上記コードに出てくるアドレスや scope などに馴染みがあると思います。認証に詳しくない場合も、上記コードは「認証に必要なエンドポイント」に対してやりたい操作 (scope) を指定して認証を行っているという程度の認識で大丈夫です。

FinishLogin の追加

StartLogin が成功すると FinishLogin が実行されます。StartLogin ではアクセストークン取得に必要なコードを得たので、 FinishLogin で実際のアクセストークンを取得します。

FinishLogin = (context, callbackUri, state) =>
    let
        parts = Uri.Parts(callbackUri)[Query],
        result = if (Record.HasFields(parts, {"error", "error_description"})) then 
                    error Error.Record(parts[error], parts[error_description], parts)
                 else
                    TokenMethod("authorization_code", "code", parts[code])
    in
        result;

TokenMethod = (grantType, tokenField, code) =>
    let
        queryString = [
            client_id = client_id,
            scope = "offline_access User.Read Calendars.Read People.Read",
            grant_type = grantType,
            redirect_uri = "https://oauth.powerbi.com/views/oauthredirect.html"
        ],
        queryWithCode = Record.AddField(queryString, tokenField, code),

        tokenResponse = Web.Contents("https://login.microsoftonline.com/organizations/oauth2/v2.0/token", [
            Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)),
            Headers = [
                #"Content-type" = "application/x-www-form-urlencoded",
                #"Accept" = "application/json"
            ],
            ManualStatusHandling = {400} 
        ]),
        body = Json.Document(tokenResponse),
        result = if (Record.HasFields(body, {"error", "error_description"})) then 
                    error Error.Record(body[error], body[error_description], body)
                 else
                    body
    in
        result;

少しコードは長いものの、取得した code を使ってアクセストークンを取得しているとだけ理解すれば大丈夫です。

shared 関数の更新

今回は /me を取得して返します。既存の share 関数を以下に書き換えます。

[DataSource.Kind="MyGraphConnector", Publish="MyGraphConnector.Publish"]
shared MyGraphConnector.Contents = () =>
    let
        source = OData.Feed("https://graph.microsoft.com/v1.0/me/", null, [ ODataVersion = 4, MoreColumns = true ])
    in
        source;

コネクターのテスト

F5 キーを押下してテストを実行します。まず認証が聞かれるため OAuth2 を選択してログインします。

委任のプロンプトが出るので「Accept」をクリックします。

ログインが成功するとアクセストークンが表示されるため、画面一番下にある「Set Credential」をクリックします。

再度 F5 キーを押下すると結果が表示されます。

Power BI デスクトップ で使う

前回記事の展開セクション を参照して Power BI デスクトップにカスタムコネクターを展開します。

Calendars.Read 権限があるため取得されたデータを展開すると予定が確認できます。

まとめ

この記事では OAuth 認証の使い方と Microsoft Graph を使ったデータ取得を見ていきました。実際にはトークンのリフレッシュやログアウトを含めもう少しコードがあった方がいいのですが、詳細はサンプルを参照してください。