Condividi tramite


Uso dell'accesso Single Sign-On in modo efficiente nella soluzione orientata ai servizi

La soluzione orientata ai servizi utilizza Enterprise Single Sign-On (SSO) per archiviare i valori di configurazione e per gestire le credenziali per i sistemi back-end. Per ridurre la latenza, la soluzione utilizza una cache locale per i valori di configurazione. La soluzione aggiorna la cache ogni cinque minuti.

In molte applicazioni gli adapter gestiscono le operazioni SSO, quali l'assegnazione di un ticket SSO, il riscatto del ticket e l'utilizzo delle credenziali per ottenere l'accesso all'applicazione affiliata. La versione inline della soluzione orientata ai servizi non utilizza tuttavia gli adapter. SSO viene infatti utilizzato dal codice.

In questo argomento vengono descritti il meccanismo di memorizzazione nella cache utilizzato dalla soluzione, nonché la modalità di utilizzo di SSO dal codice da parte della versione inline della soluzione.

Memorizzazione nella cache locale dei valori di configurazione

La soluzione orientata al servizio usa due oggetti, ConfigPropertyBag e ConfigParameters, per gestire i valori di configurazione. La classe ConfigPropertyBag contiene i valori e viene usata solo dalla classe ConfigParameters . La classe ConfigParameters viene usata dalle altre parti della soluzione per recuperare i parametri di configurazione. Entrambe le classi si trovano nello spazio dei nomi Microsoft.Samples.BizTalk.WoodgroveBank.ConfigHelper .

Nota

La soluzione orientata ai servizi utilizza un intervallo di aggiornamento della cache di 300 secondi (5 minuti). È possibile, invece, rendere l'intervallo di aggiornamento della cache una proprietà configurabile in questa soluzione. Questa operazione viene eseguita nella soluzione Gestione dei processi di business. Per altre informazioni su come la soluzione gestisce l'accesso SSO, vedere Uso efficiente dell'accesso SSO nella soluzione di gestione dei processi aziendali. Si noti che, in tal caso, la modifica dell'intervallo di aggiornamento non viene applicata fino a quando la cache non viene aggiornata al termine del precedente intervallo.

ConfigPropertyBag include i metodi seguenti:

Metodo Descrizione
Lettura Recupera un valore per una determinata proprietà.
Scrittura Assegna un valore a una proprietà.

La classe usa un'istanza di .NET NameValueCollection per contenere i valori. I due metodi di accesso implementano l'interfaccia IPropertyBag dallo spazio dei nomi Microsoft.BizTalk.SSOClient.Interop . La classe ConfigPropertyBag è una classe interna e utilizzata solo dalla classe ConfigParameters .

Nota

I nomi di chiave nell'elenco proprietà non applicano la distinzione tra maiuscole e minuscole. NameValueCollection sottostante usa i confronti di hash senza distinzione tra maiuscole e minuscole.

L'applicazione usa la classe ConfigParameters per gestire i valori di configurazione SSO. La classe dispone degli attributi e dei metodi pubblici seguenti:

Attributo o metodo Descrizione
SSOConfigParameter Enumerazione per specificare i parametri di configurazione.
GetConfigParameters Metodo utilizzato per recuperare un valore per un determinato parametro. Utilizza SSOConfigParameter per indicare il parametro.

La classe ConfigParameters usa la classe Timer .NET e una funzione delegato per configurare l'aggiornamento di 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);  
}  

Si noti che il costruttore statico inizializza le variabili dei membri statici abilitando di conseguenza l'utilizzo dei metodi della classe senza creare un'istanza della classe. Il costruttore crea istanze dell'archivio di configurazione SSO (ISSOConfigStore), il contenitore delle proprietà di configurazione (ConfigPropertyBag) e un blocco di sincronizzazione (ReaderWriterLock) usato per controllare l'accesso alla ConfigurationPropertyBag durante gli aggiornamenti e le letture. Il costruttore usa quindi GetConfigInfo per recuperare i valori di configurazione SSO e inserirli nel contenitore delle proprietà. Infine, il costruttore crea un oggetto Timer che, dopo l'intervallo specificato, chiama la funzione delegato, cacheRefreshCallback.

La funzione delegato timer è relativamente semplice:

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);  
}  

Si noti che il metodo di callback di aggiornamento della cache disabilita il timer in modo da poter essere eseguito completamente. Si noti inoltre l'utilizzo di blocchi per controllare l'accesso all'elenco proprietà. ReaderWriterLock è la scelta migliore qui, è progettata per i casi in cui sono presenti più letture rispetto alle scritture. Si noti anche che il blocco, syncLock, è statico e dichiarato a livello di classe che tutti i thread condividono la stessa istanza, singola.

Utilizzo di SSO dal codice

Quando si usa l'accesso Single Sign-On dal codice, il codice deve assumere il ruolo dell'adapter: ovvero recuperare il ticket SSO dal messaggio, riscattare il ticket per ottenere il nome utente e la password per il sistema back-end e infine usare il sistema back-end. La soluzione orientata al servizio esegue questa operazione tramite il metodo GetPendingTransactionsResponse dell'oggetto PendingTransactionsCaller .

Il metodo ha l'aspetto seguente:

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;  
    }  
}  

Il metodo inizia recuperando le informazioni di configurazione, incluso l'URL, del sistema back-end e il nome dell'applicazione back-end (affiliata).

Per riscattare il ticket, il metodo deve estrarre il ticket e il nome utente della richiesta originale dal messaggio. Il messaggio contiene il ticket come una delle proprietà del contesto del messaggio, BTS. SSOTicket. Per altre informazioni, vedere Proprietà del contesto del messaggio nella guida per l'interfaccia utente e informazioni di riferimento sullo spazio dei nomi delle API per sviluppatori. Il metodo estrae anche originatorSID dalle proprietà del contesto del messaggio. Con il ticket e il nome del creatore a disposizione, il metodo chiama il metodo RedeemTicket sul ticket per recuperare le credenziali.

La parte restante del codice crea una cache NetworkCredential .NET per le credenziali e chiama il servizio Web back-end.

Nota

Poiché il nome utente e la password provengono da SSO come testo non crittografato, è consigliabile ridurre al minimo la durata delle variabili contenti tali informazioni. Si noti che il codice dichiara le variabili delle credenziali all'interno di un blocco try . In questo caso, le variabili scadono all'uscita dal blocco try .

Vedere anche

Implementazione della soluzione orientata ai servizi