服務導向解決方案會使用 Enterprise Single Sign-On (SSO) 來儲存組態值,以及處理後端系統的認證。 為了減少延遲,解決方案會針對組態值使用本機快取。 解決方案每隔五分鐘重新整理一次快取。
在許多應用程式中,配接器會處理 SSO 作業,包括取得 SSO 票證、兌換票證,以及使用認證來取得聯盟應用程式的存取權。 不過,服務導向解決方案的內嵌版本不會使用配接器。 它必須在程式碼中使用 SSO。
本主題描述了解決方案所使用的快取機制,以及解決方案的嵌入式版本如何從程式碼中使用 SSO。
組態值的本機快取
服務導向解決方案會使用兩個物件 ConfigPropertyBag 和 ConfigParameters 來處理組態值。 ConfigPropertyBag 類別會保存值,而且只能由 ConfigParameters 類別使用。 方案的其他部分會使用 ConfigParameters 類別來擷取組態參數。 這兩個類別都在 Microsoft.Samples.BizTalk.WoodgroveBank.ConfigHelper 命名空間中。
備註
服務導向解決方案會將快取重新整理間隔修正為300秒(5分鐘)。 您可以改為想要讓快取重新整理間隔本身成為此解決方案中的可設定屬性。 這是在商務程式管理解決方案中完成的。 如需該解決方案如何處理 SSO 的詳細資訊,請參閱 在商務程式管理解決方案中有效率地使用 SSO。 請注意,在這種情況下,只有當舊的間隔時間結束並快取被重新整理後,重新整理間隔中的變更才會生效。
ConfigPropertyBag 具有下列方法:
| 方法 | 說明 |
|---|---|
| 參閱 | 擷取指定屬性的值。 |
| 書寫 | 將值指派給屬性。 |
類別會使用 .NET NameValueCollection 的實例來保存值。 這兩個存取方法會從 Microsoft.BizTalk.SSOClient.Interop 命名空間實作 IPropertyBag 介面。 ConfigPropertyBag 類別是內部類別,只能由 ConfigParameters 類別使用。
備註
屬性包中的索引鍵名稱不區分大小寫。 基礎 NameValueCollection 會使用不區分大小寫的哈希函數和不區分大小寫的比較。
應用程式會使用 ConfigParameters 類別來處理 SSO 組態值。 類別具有下列公用方法和屬性:
| 方法或屬性 | 說明 |
|---|---|
| SSOConfig參數 | 指定組態參數的列舉。 |
| GetConfigParameters | 用來擷取指定參數值的方法。 使用 SSOConfigParameter 來指出 參數。 |
ConfigParameters 類別會使用 .NET Timer 類別和委派函式來設定 ConfigPropertyBag 的重新整理:
private static Timer cacheRefreshTimer;
private static ISSOConfigStore ssoConfigStore;
private static ReaderWriterLock syncLock;
// Cache refresh interval in milliseconds
private const int CacheRefreshInterval = 5 * 60 * 1000;
private static ConfigPropertyBag ssoPropBag;
static ConfigParameters()
{
ssoConfigStore = new ISSOConfigStore();
ssoPropBag = new ConfigPropertyBag();
syncLock = new ReaderWriterLock();
ssoConfigStore.GetConfigInfo(SSO_CONFIG_APP,
SSO_IDENTIFIER_NAME, SSOFlag.SSO_FLAG_RUNTIME,
ssoPropBag);
cacheRefreshTimer = new Timer(
new TimerCallback(ConfigParameters.cacheRefreshCallback),
null, CacheRefreshInterval, CacheRefreshInterval);
}
請注意,靜態建構函式會初始化靜態成員變數,如此便能使用類別方法,而不需要建立 類別的實例。 建構函式會建立 SSO 組態存放區 (ISSOConfigStore) 的實例、組態屬性包 (ConfigPropertyBag),以及用來控制更新和讀取期間 ConfigurationPropertyBag 存取權的同步處理鎖定 (ReaderWriterLock)。 建構函式接著會使用 GetConfigInfo 來擷取 SSO 組態值,並將其放入屬性包中。 最後,建構函式會建立 Timer 物件,在指定的間隔之後呼叫委派函式 cacheRefreshCallback。
定時器委派函式相當簡單:
private static void cacheRefreshCallback(object state)
{
// Disable the timer until we are done loading the cache.
cacheRefreshTimer.Change(Timeout.Infinite, CacheRefreshInterval);
// Put the data from SSO in a new property bag so that
// we don't have to lock the property bag and block it from being
// used. The SSO call is a remote call and may take a while.
ConfigPropertyBag propBag2 = new ConfigPropertyBag();
ssoConfigStore.GetConfigInfo(SSO_CONFIG_APP,
SSO_IDENTIFIER_NAME, SSOFlag.SSO_FLAG_RUNTIME, propBag2);
// Get a writer lock before updating the cached values.
syncLock.AcquireWriterLock(Timeout.Infinite);
try
{
ssoPropBag = propBag2;
}
finally
{
syncLock.ReleaseWriterLock();
}
// Enable the timer.
cacheRefreshTimer.Change(CacheRefreshInterval,
CacheRefreshInterval);
}
請注意,快取重新整理回呼方法會停用定時器,讓方法可以一路執行。 另請注意,使用鎖定來控制屬性包的存取。 ReaderWriterLock 是這裡的最佳選擇,它是專為讀取比寫入更多的案例所設計。 另請注意,鎖 syncLock 是靜態宣告的,並在類別層級中宣告,所有線程共用相同的單一實例。
從程式代碼使用 SSO
從程式代碼使用單一登錄時,程式代碼必須承擔配接器的角色:也就是從訊息擷取 SSO 票證、兌換票證以取得後端系統的使用者名稱和密碼,最後使用後端系統。 服務導向解決方案會透過PendingTransactionsCaller物件的 GetPendingTransactionsResponse 方法執行這項作。
方法如下所示:
public static PendingTransactionsResponse GetPendingTransactionsResponse(XLANGMessage requestMsg)
{
try
{
// Get config parameter values.
int ptTimeout = Convert.ToInt32(
ConfigParameters.GetConfigParameter(
ConfigParameters.
SSOConfigParameter.
PENDING_TRANSACTIONS_INLINE_TIMEOUT
)
);
string ptURL = ConfigParameters.GetConfigParameter(
ConfigParameters.
SSOConfigParameter.
PENDING_TRANSACTIONS_URL
);
string ssoAffliateApp = ConfigParameters.
GetConfigParameter(ConfigParameters.
SSOConfigParameter.
PENDING_TRANSACTIONS_SSO_AFFILIATE_APP
);
// Redeem the SSO ticket and get the userid/password to
// use to interact with Pending Transaction System.
// Extract the ticket…
string msgTicket = (string)requestMsg.
GetPropertyValue(typeof(BTS.SSOTicket));
// and the user name of the originating user.
string originatorSID = (string)requestMsg.
GetPropertyValue(
typeof(
Microsoft.BizTalk.XLANGs.BTXEngine.OriginatorSID
)
);
string pendTransUserName;
// Now, redeem the ticket.
string[] pendTransCredential =
ssoTicket.RedeemTicket(
ssoAffliateApp,
originatorSID,
msgTicket,
SSOFlag.SSO_FLAG_NONE,
out pendTransUserName
);
PendingTransactionsRequest req =
(PendingTransactionsRequest)requestMsg[0].
RetrieveAs(
typeof(PendingTransactionsRequest)
);
PendingTransactionsResponse resp;
using (PendingTransactionsWebService
svc = new PendingTransactionsWebService())
{
svc.Url = ptURL;
svc.Timeout = ptTimeout;
// The web service uses basic authentication, so we
//need to send the user id and password in the request.
CredentialCache credCache = new CredentialCache();
NetworkCredential credentialToUse =
new NetworkCredential(
pendTransUserName, pendTransCredential[0]
);
credCache.Add(new Uri(svc.Url), "Basic", credentialToUse);
svc.Credentials = credCache;
resp = svc.GetPendingTransactions(req);
}
return resp;
}
catch (System.Net.WebException webEx)
{
if (webEx.Status == WebExceptionStatus.Timeout)
{
throw new PendingTransactionsTimeoutException();
}
else
{
Trace.WriteLine("Other Net.WebException: "
+ webEx.ToString()
+ (null == webEx.InnerException ? "" :
("Inner Exception: "
+ webEx.InnerException.ToString())
)
);
throw;
}
}
catch(System.Exception ex)
{
Trace.WriteLine("Other Exception: "
+ ex.ToString()
+ (null == ex.InnerException ? "" :
("Inner Exception: "
+ ex.InnerException.ToString())
)
);
throw;
}
}
方法一開始會擷取後端系統的組態資訊,包括URL,以及後端(分支機構) 應用程式的名稱。
若要兌換票證,方法必須從訊息中擷取票證和原始要求用戶名稱。 訊息內容屬性之一 BTS.SSOTicket 包含票證。 如需詳細資訊,請參閱UI指引中的訊息內容屬性和開發人員 API 命名空間參考。 方法也會從訊息內容屬性擷取 OriginatorSID 。 方法會使用票證和發起者的名稱,呼叫票證上的 RedeemTicket 方法以擷取憑證。
其餘的程式代碼會為認證建立 .NET NetworkCredential 快取,並呼叫後端Web服務。
備註
因為使用者名稱和密碼會以純文本從 SSO 傳回,因此您想要將保留該資訊的變數存留期降到最低。 請注意,程序代碼會在 try 區塊內宣告認證變數。 在這裡,變數會在 try 區塊結束時到期。