SharePoint Framework では AadHttpClient を使うことで Azure Active Directory で保護された API に対してのアクセスを OAuth の設定を行うことなく簡単に実装することができます。ということは Common Data Service (Dynamics 365) のデータにもアクセスできるはずなので試してみたいと思います。
事前準備
通常、SahrePoint Framework に対して Web API へのアクセス許可を与えるためには、package-solution.json に webApiPermissionRequests を記述する必要があります。この記述にしたがって、SharePoint 管理センターで API のアクセス許可を承認することができるようになるのですが、Common Data Service の場合、次のように記述しても実はうまくいきません。
{ "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", "solution": { "name": "MyApplication", "id": "ad9139c7-12db-470b-937d-54967f418959", "version": "1.0.0.0", "includeClientSideAssets": true, "isDomainIsolated": false, "webApiPermissionRequests": [ { "resource": "Common Data Service", "scope": "user_impersonation" } ] }, "paths": { "zippedPackage": "solution/sharepoint-framework-read-dynamics.sppkg" } }
これは、Common Data Service という名前のサービス プリンシパルが複数あり、表示名で紐づけしようとすると別のサービス プリンシパルに結びついてしまうことが原因のようです。SharePoint Framework の問題なのですが、公式でも表示名を指定するように注釈があるため、なんらかの原因があると考えています。
resource プロパティの値には、アクセス許可を要求するアプリケーションの displayName を指定する必要があります。 リソースの指定に objectId を使用すると、アクセス許可の要求を承認しようとしたときにエラーが発生します。
ということで、Common Data Service へのアクセス許可を与えるために、Azure ポータルで操作することになります。SharePoint Framework は「SharePoint Online Client Extensibility Web Application Principal」というアプリケーションに対してアクセス許可を与えています。直接このアプリケーションを編集することで SharePoint 管理ポータルでの承認と同じことを行うことができます。
SharePoint 管理ポータルから見たときも承認された要求として表示されています。ただし SharePoint Framework のアプリ名などのメタ情報は表示されないみたいですね。
ともあれ、これで Common Data Service に接続できるようになりました。
サンプル コード
src/webparts/my-application/MyApplicationWebPart.ts
お約束として context を渡しておくのを忘れないようにします。endpoint は Dynamics 365 の URL を表します。
export default class MyApplicationWebPart extends BaseClientSideWebPart<IMyApplicationWebPartProps> { public render(): void { const element: React.ReactElement<IMyApplicationProps> = React.createElement( MyApplication, { context: this.context, endpoint: this.properties.endpoint } ); ReactDom.render(element, this.domElement); } }
src/webparts/my-application/components/MyApplication.tsx
componentDidMount メソッドで AadHttpClient を使って Common Data Service Web API への要求を行います。今回は標準のエンティティのデータを取得しますが、カスタム エンティティについても同様に取得が可能です。
export default class MyApplication extends React.Component<IMyApplicationProps, IMyApplicationState> { public componentDidMount(): void { if (this.props.endpoint == null) { return; } this.props.context.aadHttpClientFactory .getClient(this.props.endpoint) .then((client: AadHttpClient) => { client .get(this.props.endpoint + "/api/data/v9.0/accounts", AadHttpClient.configurations.v1) .then((response: HttpClientResponse) => response.json()) .then((response: any) => { this.setState({ accounts: response.value as Array<IAccount> }); }); }); } }
実行結果
実行すると以下のようにエンティティのデータが取得できていることを確認できます。なお、Common Data Service のライセンス (Power Apps や Dynamics 365 Sales など) がないユーザーの場合は表示できませんのでご注意ください。
まとめ
直接 Azure Active Directory のアプリケーションを操作するというのがいささかトリッキーではあるのですが、使えるテクニックなのでぜひお試しいただければと思います。