Dynamics CRM 2011 トークンの有効期限と更新
みなさん、こんにちは。
今回は SDK プログラムで欠かせないサービスへの接続に関するTips です。
Dynamics CRM 2011 は WCF ベースのサービスを提供するため、数多くのタイムアウト設定が
ありますが、意外と見落としがちなのが、トークンの有効期限です。トークンの期限が切れた
状態でサービスのメソッドを実行すると、エラーになってしまいます。
トークンの有効期限確認
早速以下の手順で Dynamics CRM オンラインに対してサービスを生成してみます。
1. Visual Studio 2010 より、新規プロジェクトを作成。コンソールアプリを選択してください。
プロジェクト作成後、利用する .NET Framework を .NET Framework 4.0 にします。
2. 参照設定より以下の内容を追加します。
参照
Microsoft.Xrm.Sdk.dll アセンブリ
.NET
System.ServiceModel
System.Runtime.Serialization
System.Security
Microsoft.IdentityModel
System.IdentityModel
3. 既存の項目として以下のファイルを追加します。
sdk\samplecode\cs\helpercode\crmservicehelpers.cs
sdk\samplecode\cs\helpercode\deviceidmanager.cs
4. Program.cs を以下のように編集します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using Microsoft.IdentityModel;
using Microsoft.Crm.Sdk.Samples;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Crm.Sdk.Messages;
using System.Threading;
namespace TokenLife
{
class Program
{
private OrganizationServiceProxy _serviceProxy;
static void Main(string[] args)
{
// ヘルパークラスを利用して認証情報等収集
ServerConnection serverConnect = new ServerConnection();
ServerConnection.Configuration config = serverConnect.GetServerConfiguration();
Program app = new Program();
app.Run(config, true);
}
public void Run(ServerConnection.Configuration serverConfig, bool promptForDelete)
{
try
{
// ヘルパークラスを利用して、組織サービスの生成
using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri,
serverConfig.HomeRealmUri,
serverConfig.Credentials,
serverConfig.DeviceCredentials))
{
// WhoAmI リクエストを実行
WhoAmIRequest req= new WhoAmIRequest();
_serviceProxy.Execute(req);
if (null != _serviceProxy.SecurityTokenResponse)
{
// トークンの有効範囲を表示
var Token = _serviceProxy.SecurityTokenResponse.Token;
Console.WriteLine("Token Start at: " + Token.ValidFrom.ToLocalTime().ToString());
Console.WriteLine("Token Expire at: " + Token.ValidTo.ToLocalTime().ToString());
}
}
}
catch
{
}
}
}
}
5. 最後の Console.WriteLine にブレークポイントを仕掛けて、実行します。
6. 今回はオンラインで検証したため、CRM サーバー名は crm5.dynamics.com
ユーザー名は Live ID を指定して、実行。組織の一覧から、実行対象を選択。
7. 実行結果からトークンは 8 時間有効であることが確認できます。
トークンの更新
1. 先ほどのメソッドの一部を以下のように書き換えます。
// ヘルパークラスを利用して、組織サービスの生成
using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri,
serverConfig.HomeRealmUri,
serverConfig.Credentials,
serverConfig.DeviceCredentials))
{
// WhoAmI リクエストを実行
WhoAmIRequest req= new WhoAmIRequest();
_serviceProxy.Execute(req);
if (null != _serviceProxy.SecurityTokenResponse)
{
// トークンの有効範囲を表示
var Token = _serviceProxy.SecurityTokenResponse.Token;
Console.WriteLine("Token Start at: " + Token.ValidFrom.ToLocalTime().ToString());
Console.WriteLine("Token Expire at: " + Token.ValidTo.ToLocalTime().ToString());
}
// 10 秒スリープ
Thread.Sleep(10000);
// トークンの更新
_serviceProxy.Authenticate();
if (null != _serviceProxy.SecurityTokenResponse)
{
// トークンの有効範囲を表示
var Token = _serviceProxy.SecurityTokenResponse.Token;
Console.WriteLine("Token Start at: " + Token.ValidFrom.ToLocalTime().ToString());
Console.WriteLine("Token Expire at: " + Token.ValidTo.ToLocalTime().ToString());
}
}
2. 最後の Console.WriteLine にブレークポイントを設定してから、
再度プログラムを実行します。今回はヘルパークラスを利用して
接続を作成しているため、2 回目の実行では前回使用した情報を
再利用できます。
3. 実行結果からトークンが更新されていることが確認できます。
トークンの自動更新
随時 Authenticate をしていけばトークンは更新されますが、各処理の
前にコードを入れていくことは煩わしいですし、不要な更新が増えることにも
なります。そこで最新の SDK にもあるように、独自のクラスを利用してその
処理を自動化してみます。
1. プロジェクトに新しくクラスを追加します。名前はMyOrganizationServiceProxy.cs
としてみました。任意で結構です。
2. 以下のように OrganizationServiceProxy を継承します。
class MyOrganizationServiceProxy : OrganizationServiceProxy
3. 変数の宣言とクラスのコンストラクタを作成します。単純に継承元の
コンストラクタを呼出して、インスタンスに代入しているだけです。
private MyOrganizationServiceProxy _serviceProxy;
public MyOrganizationServiceProxy(Uri serviceUri, Uri homeRealmUri,
ClientCredentials userCredentials, ClientCredentials deviceCredentials)
: base(serviceUri, homeRealmUri, userCredentials, deviceCredentials)
{
_serviceProxy = this;
}
4. ValidateAuthentication を上書きします。ValidateAuthentication
の詳細は SDK を参照してください。また上書きした中でトークンの更新用
メソッドを追加します。
protected override void ValidateAuthentication()
{
// トークンの更新
RenewTokenIfRequired();
base.ValidateAuthentication();
}
5. トークンの更新用メソッドを追加します。ここでプロキシの SecurityTokenResponse
を確認して、存在する場合にはトークンの有効期限を確認しています。残り 15 分以下、
または、既に期限が切れている場合に、Authenticate メソッドを呼び出してトークンを
更新します。
public void RenewTokenIfRequired()
{
if (null != this._serviceProxy.SecurityTokenResponse &&
DateTime.Now.ToUniversalTime().AddMinutes(15) >=
this._serviceProxy.SecurityTokenResponse.Response.Lifetime.Expires)
{
try
{
this._serviceProxy.Authenticate();
}
catch (CommunicationException)
{
if (null == this._serviceProxy.SecurityTokenResponse ||
DateTime.Now >= this._serviceProxy.SecurityTokenResponse.Response.Lifetime.Expires)
{
throw;
}
}
}
}
6. Program.cs に戻り、新しく作成したクラスを利用するよう一部コードを変更します。
変数宣言部
// private OrganizationServiceProxy _serviceProxy;
private MyOrganizationServiceProxy _serviceProxy;
プロキシ生成部
//using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri,
// serverConfig.HomeRealmUri,
// serverConfig.Credentials,
// serverConfig.DeviceCredentials))
using (_serviceProxy = new MyOrganizationServiceProxy(serverConfig.OrganizationUri,
serverConfig.HomeRealmUri,
serverConfig.Credentials,
serverConfig.DeviceCredentials))
自動更新にするため Authenticate() は不要
// _serviceProxy.Authenticate();
7. 違いを見るために、以下の 2 箇所にブレークポイントを仕掛けます。
- 各サービスメソッド実行部分
- MyOrganizationServiceProxy.cs の ValidateAuthentication 内部
8. プログラムを実行します。サービスのメソッドが実行されるタイミングで、新しく作成した
クラスの ValidateAuthentication が呼び出され、トークンの更新が必要か確認します。
あとはオンラインの場合には 8 時間、クレーム認証の場合には ADFS のトークン生存
時間を目処に検証してみてください。
まとめ
今回のコードは プラグインレジストレーションツールにあるものから借用しただけのもので、
完全なコードは以下のファイルにあります。実際に利用する場合には、これらのファイルを
確認していただき、必要な対処を行ってください。
sdk\tools\pluginregistration フォルダ
autorefreshsecuritytoken.cs
toolserviceproxies.cs
参考情報:
Claims-based authentication and security token expiration
https://technet.microsoft.com/en-us/library/gg188586.aspx
- Dynamics CRM サポート 中村 憲一郎