松崎 剛 Blog

This Blog's theme : エンタープライズ開発 (Server side)、Office サーバ開発

SharePoint の Cross-domain library

SharePoint の Cross-domain library

  • Comments 0

環境 :
Visual Studio 2012
Microsoft Office Developer Tools for Visual Studio 2012 Preview
Office 365 Preview (SharePoint Online Preview)

SharePoint 2013 Apps 開発

こんにちは。

今回は、SharePoint 2013 で提供されている Cross-domain library について説明します。(間があいてしまい、すみません。忙殺されてました。。。)

 

Cross-domain library の動作

前回説明したように、SharePoint App (App for SharePoint 2013) で、Remote App (test1.cloudapp.net など) から SharePoint のサーバー (contoso-xxxxx.sharepoint.com など) に JavaScript を使ってアクセスする場合、クロスドメイン (Cross-domain) の問題を克服する必要があります。また、認証スキーマにも配慮する必要があります。
SharePoint 2013 の Cross-domain library は、まさにこうしたケースを解決するために提供されているライブラリーです。

Cross-domain library では、XDM (Cross document messaging) による iframe を使った Message Post が使用されています。(XDM については、以前 投稿した「開発者にとっての Internet Explorer」を参照してください。)
例えば、今、Web アプリケーション (Remote App) が test1.cloudapp.net のドメインで動いていると仮定します。Cross-domain library は、contoso-xxxxx.sharepoint.com で動いている SharePoint のページを hidden の iframe で挿入し、iframe (contoso-xxxxx.sharepoint.com) の中の処理を XDM を使って呼び出します。つぎに、iframe (contoso-xxxxx.sharepoint.com) のページは、Ajax などを使用して contoso-xxxxx.sharepoint.com のサーバー サイド処理を呼び出し、結果を XDM を通して、元の Web アプリケーション (test1.cloudapp.net) に返します。(下図)
この流れでは、いっさいクロスドメインの呼び出しはおこなわれません。

Cross-domain library の実体は、このあと見るように、SharePoint 2013 の SP.RequestExecutor.js です。開発者は、このライブラリーの関数を呼び出すことで、上記の流れを意識せず、クロスドメインの呼び出し (上述) が可能です。内部では、iframe として、_layouts/15/AppWebProxy.aspx が挿入されます。

クロスドメイン (Cross-domain) を克服する手法には、JSONP など、さまざまな手法がありますが、この iframe を使用した方式が、他の方式より優れている点は、Claim Base 認証との相性が非常に良いという点です。
例えば、_layouts/15/AppWebProxy.aspx の挿入 (ifarme の挿入) をおこなう際、SharePoint (または、SharePoint Online) へのログインが必要となりますが、Remote App の場合、通常は、既に SharePoint へのログインを完了した後のため、特別な認証処理をおこなう必要はなく、ブラウザーがすべて解決してくれます。なお、前回の「Apps for SharePoint の動作と概要」で説明したように、SharePoint 2013 には、Host Web、App Web の 2 つの概念がありますが、Windows Azure Active Directory など Claim Base の認証を使用している場合には、いずれのサイトも Web SSO (シングル サインオン) で処理されます。(iframe を使うことによって、ブラウザーが、認証処理を解決してくれます。)
SharePoint (Host web など) への接続がおこなわれていない外部アプリケーションから、勝手に この Cross-domain library を呼び出すこともできません。

 

App Web へのアクセス - REST API

では、実際に使い方を見てみましょう。(App for SharePoint 2013 の基本的な概念については、あらかじめ、「Apps for SharePoint の動作と概要」を参照しておいてください。ここでは、SharePoint App の詳しい説明は省略します。)

まずは、REST を使って、Remote App から App Web にアクセスしてみましょう。

App for SharePoint 2013 のプロジェクトを新規作成します。(今回、Provider-hosted として作成します。)
Apps for SharePoint の動作と概要」で説明したように、AppManifest.xml をダブルクリックして、適切な Permission を設定しておきましょう。(下記のサンプルでは、Web の Read 権限を付与すれば充分です。)

プロジェクトを新規作成すると、マニフェスト (AppManifest.xml) には下記の通り設定されています。(下記は、何も変更していません。) 以降で使用する SPAppWebUrl、SPHostUrl などの Query String は、下記の StandardTokens トークンに設定されて渡されるのでおぼえておいてください。

<?xml version="1.0" encoding="utf-8" ?>
<App xmlns=" . . .>
  <Properties>
    <Title>SharePointApp1</Title>
    <StartPage>~remoteAppUrl/Pages/Default.aspx?{StandardTokens}</StartPage>
  </Properties>
  . . .

また、プロジェクトで作成された Page_Load イベントの処理は、今回は使用しないので削除しておきます。(すべて、JavaScript で作成しますので不要です。)

Provider-hosted のプロジェクトでは Remote App は作成されますが、App Web は作成されません。今回は、Cross-domain library で呼び出される App Web を作成する必要があるため、App のプロジェクトを右クリックして、[Add] - [New Item] で「List1」という名前のリストを追加しておきます。これにより、App の追加と同時に App Web も作成されるようになります。(同時に、「List1」という名前のリスト インスタンスも作成されます。)

Web アプリケーション (Remote App) のプロジェクトの Default.aspx (マークアップ コード) を開き、script タグで、SP.RequestExecutor.js への参照を追加します。SharePoint 2013 のサイトにある _layouts/15/SP.RequestExecutor.js を直接参照しても OK ですが、今回は、下記の通り、このファイルを Scirpts フォルダーにコピーして参照します。(なお、SharePoint 上の _layouts/15/SP.RequestExecutor.js は、認証なしで参照できます。)

. . .
<head runat="server">
  . . .
  <script src="../Scripts/jquery-1.6.2.js" type="text/javascript"></script>
  <script src="../Scripts/SP.RequestExecutor.js" type="text/javascript"></script>
</head>
. . .

HTML のボタン (Button1) を配置し、下記の通りコードを記述します。
このコードでは、App Web の List1 (上記) からリスト アイテムをすべて取得し、アイテムのタイトルを alert で表示します。

なお、「Apps for SharePoint の動作と概要」で解説した通り、SharePoint 2013 では新しい REST API が提供されており、ここでは、この REST API を使用しています。

. . .
<script type="text/javascript">
  var appweburl;

  $(document).ready(function () {
    appweburl = getParameterByName('SPAppWebUrl');

    $('#Button1').click(function () {
      var executor = new SP.RequestExecutor(appweburl);
      executor.executeAsync({
        url: appweburl +
          '/_api/web/lists/getbytitle(\'List1\')/items',
        method: 'GET',
        headers: {'Accept': 'application/json; odata=verbose' },
        success: successHandler,
        error: errorHandler
      });
    });
  });

  function successHandler(data) {
    var jsonObject = JSON.parse(data.body);
    var results = jsonObject.d.results;
    for (var i = 0; i < results.length; i++) {
      alert(results[i].Title);
    }
  }

  function errorHandler(data, errorCode, errorMessage) {
    alert('error : ' + errorMessage);
  }

  function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
    var regexS = "[\\?&]" + name + "=([^&#]*)";
    var regex = new RegExp(regexS);
    var results = regex.exec(window.location.search);
    if (results == null)
      return "";
    else
      return decodeURIComponent(results[1].replace(/\+/g, " "));
  }
</script>

<form id="form1" runat="server">
<div>
  <input id="Button1" type="button" value="Button1" />
</div>
</form>
. . .

前述の通り、Web SSO により認証されるため、認証に関する特別なプログラミングはいっさい不要です。(一方、JavaScript を使わず、サーバー側からアクセスする場合には、「Apps for SharePoint の動作と概要」で解説したように、認証のための難解なプログラミングが必要でした。)

では、動作を確認してみましょう。
SharePoint に、この App を追加したら、下記の URL を入力して List1 にアイテムをいくつか登録しておきましょう。

http://<app web url>/Lists/List1

あとは、[Site Contents] 画面に表示されている Remote App をクリックし、表示される画面でボタン (Button1) をクリックします。すると、alert によって、登録されたアイテムの Title が順番に表示されます。

内部では、クラウド上 (Azure など) に配置された Remote App の JavaScript から、App Web (SharePoint) のリストに REST を使ってアクセスしています。ボタン (Button1) を Click すると、前述の通り、App Web の _layouts/15/AppWebProxy.aspx が iframe として挿入されます。この様子は、Fiddler や、Internet Explorer の開発者ツール (下図) などで確認できます。

この URL (App Web の _layouts/15/AppWebProxy.aspx) に接続するには、もちろん、認証処理が必要ですが、既にこのアプリケーションを表示する前に Microsoft Online Services (Windows Azure Active Directory) などクレームベースによる認証処理 (ログイン) をおこなっているため、認証画面は表示されず、AppWebProxy.aspx のドキュメントが使用できます。(Web SSO)

 

Host Web へのアクセス - REST API

上記は、App Web に登録したリスト インスタンス (List1) のデータを取得するサンプルですが、「Apps for SharePoint の動作と概要」で解説した新しい REST API を使用して Host Web (SharePoint) のデータにもアクセスできます。

例えば、下記は、Host Web (SharePoint) に作成した TestList1 というカスタム リストのアイテムを取得し、アイテムの Title を alert で表示します。(太字が、追加・変更したコードです。その他のコードは、上記と同じです。)
下記の通り、App Web 上の REST サービスに接続し、そこから Host Web にアクセスできます。

. . .
var hostweburl;

var appweburl;

$(document).ready(function () {
  hostweburl = getParameterByName('SPHostUrl');
  appweburl = getParameterByName('SPAppWebUrl');

  $('#Button1').click(function () {
    var executor = new SP.RequestExecutor(appweburl);
    executor.executeAsync({
      url: appweburl +
        '/_api/SP.AppContextSite(@target)/web/lists/getbytitle(\'TestList1\')/items?@target=\'' +
        hostweburl + '\'',
      method: 'GET',
      headers: {'Accept': 'application/json; odata=verbose' },
      success: successHandler,
      error: errorHandler
    });
  });
});
. . .

 

JavaScript OM (JSOM) の使用

上記では Cross-domain library を使用して REST API を呼び出すサンプルですが、Cross-domain library を使用して JavaScript の CSOM (Client Side Object Model, JSOM) を使用することもできます。

まず、/_layouts/15 下にある JavaScript CSOM (JSOM) のライブラリーを参照追加します。今回は、下記 (太字) の通り、SP.Runtime.js、SP.js のみを使用します。(今回は、Scripts フォルダーに、これらをコピーしています。)

<head runat="server">
  . . .
  <script src="../Scripts/jquery-1.6.2.js" type="text/javascript"></script>
  <script
    src="http://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"
    type="text/javascript"></script>
  <script src="../Scripts/SP.Runtime.js" type="text/javascript"></script>
  <script src="../Scripts/SP.js" type="text/javascript"></script>
  <script src="../Scripts/SP.RequestExecutor.js" type="text/javascript"></script>
</head>

JSOM を使って App web の List1 からアイテムの一覧を取得するには、以下の通りコードを記述します。

. . .
var hostweburl;
var appweburl;
var web;
var list;
var items;

$(document).ready(function () {
  hostweburl = getParameterByName('SPHostUrl');
  appweburl = getParameterByName('SPAppWebUrl');

  $('#Button1').click(function () {
    var context = new SP.ClientContext(appweburl);
    var factory = new SP.ProxyWebRequestExecutorFactory(
      appweburl);
    context.set_webRequestExecutorFactory(factory);
    var appctx = new SP.AppContextSite(context, appweburl);
    web = appctx.get_web();
    list = web.get_lists().getByTitle('List1');
    var camlString = '<View><ViewFields>' +
      '<FieldRef Name=\'Title\' />' +
      '</ViewFields></View>';
    var camlQuery = new SP.CamlQuery();
    camlQuery.set_viewXml(camlString);
    items = list.getItems(camlQuery);
    context.load(items, 'Include(Title)');
    context.executeQueryAsync(
      Function.createDelegate(this, successHandler2),
      Function.createDelegate(this, errorHandler2));
  });
});

function successHandler2(data, req) {
  var enumerator = items.getEnumerator();
  while (enumerator.moveNext()) {
    var item = enumerator.get_current();
    alert(item.get_item('Title'));
  }
}

function errorHandler2(sender, args) {
  alert('error : ' + args.get_message());
}
. . .

また、JSOM でも、前述のように、host web へのアクセスが可能です。下記の 1 行を変更します。

var appctx = new SP.AppContextSite(context, hostweburl);

 

App web から Remote app の呼び出し

上記は、Remote app から App web のサービスを呼び出すサンプルですが、逆に、Cross-domain library を使って、App web から Remote app 上のサービス (REST API など) を呼び出すこともできます。(例えば、App web に配置した Page モジュールから、独自のサーバー サイド ロジックの呼び出しができます。)

上記では、SharePoint が提供している Proxy page (AppWebProxy.aspx) を使用していましたが、この場合には、Custom の Proxy page を開発者自らが構築し、これを使用します。ここでは、この詳細の手順は説明しませんが、このサンプル コードは、「MSDN : SharePoint 2013: Get data by using a proxy page for the cross-domain library」からダウンロードできますので、参考にしてください。

 

Cross-domain library の Security

上述の通り、Cross-domain library では、Claim Base 認証を使って、安全に、ドメインをまたがった連携ができます。

では、いったんブラウザーを使って Host web などにログインすれば、Remote app 以外の外部のアプリケーションから、勝手に この API を呼び出せてしまうのでしょうか ? 答えは、No です。

ユーザーが App のインストール (App の追加) をおこなうと、App web には接続可能なドメイン (Remote App のドメイン) の情報が登録されます。Cross-domain library を使用する際には、この許可されたドメインからの呼び出しかどうか検査がおこなわれ、違反している場合にはエラー (RE_DomainDoesNotMatch, -1004) が返されます。(iframe は挿入されますが、JavaScript の呼び出しがブロックされます。) なお、Custom の Proxy page を使用する場合には、この確認の処理を開発者自らがプログラミングします。

補足 : 許可するドメインは、アプリケーション マニフェスト (AppManifest.xml) の中に AllowedRemoteHostUrl 属性を使って指定できます。詳細は、「MSDN : (How to) Access SharePoint 2013 data from remote apps using the cross-domain library」を参照してください。

また、Internet Explorer を使って、ゾーン (Zone) を超えたドメイン間で Cross-domain library を使用する場合も注意が必要です。Windows の 整合性レベル (Integrity level) の観点から、いくつかの制約があるためです。ここでは、詳細の説明は省略しますが、ゾーン (Zone) をまたがった Cross-domain library の留意点については、「MSDN : Work with the cross-domain library across different Internet Explorer security zones in apps for SharePoint」に記載されていますので参考にしてください。

 

Leave a Comment
  • Please add 2 and 8 and type the answer here:
  • Post