Implementazione di IMFNetCredentialManager
Nel metodo IMFNetCredentialManager::BeginGetCredentials eseguire le operazioni seguenti.
- Se non si dispone già di un puntatore FMNetCredentialCache , chiamare MFCreateCredentialCache per creare l'oggetto cache delle credenziali. Archiviare questo puntatore.
- Chiamare IMFNetCredentialCache::GetCredential. Impostare i flag nel parametro dwAuthenticationFlags come indicato di seguito:
- Se il membro hrOp della struttura MFNetCredentialManagerGetParam è uguale a NS_E_PROXY_ACCESSDENIED, impostare il flag di MFNET_AUTHENTICATION_PROXY .
- Se fClearTextPackage è TRUE, impostare il flag di MFNET_AUTHENTICATION_CLEAR_TEXT .
- Se fAllowLoggedOnUser è TRUE, impostare il flag di MFNET_AUTHENTICATION_LOGGED_ON_USER .
- Il metodo GetCredential restituisce un puntatore FMNetCredential e possibilmente il flag di REQUIRE_PROMPT. Archiviare il puntatore IMFNetCredential .
- Se GetCredential non restituisce il flag di REQUIRE_PROMPT , viene eseguito. Passare al passaggio 9.
- In caso contrario, se GetCredential restituisce il flag di REQUIRE_PROMPT , è necessario richiedere all'utente il nome utente e la password.
- Se fClearTextPackage è FALSE, crittografare le credenziali.
- Chiamare FMINetCredential::SetUser e FMNetCredential::SetPassword per impostare il nome e la password dell'utente nell'oggetto credenziali.
- Facoltativamente, chiamare FMNetCredentialCache::SetUserOptions per aggiornare l'oggetto cache delle credenziali con le preferenze dell'utente per l'archiviazione e l'invio di credenziali.
- Richiamare il callback FMAsyncCallback chiamando MFInvokeCallback.
Nel metodo IMFNetCredentialManager::EndGetCredentials restituire il puntatore IMFNetCredential ottenuto nel metodo BeginGetCredentials .
Nel metodo IMFNetCredentialManager::SetGood passare i parametri di input direttamente al metodo FMNetCredentialCache::SetGood . In questo modo viene notificata la cache delle credenziali se le credenziali sono state accettate dal server.
Se è necessario richiedere all'utente (passaggio 5) o crittografare le credenziali (passaggio 6), è consigliabile eseguire questa operazione in un thread della coda di lavoro, in modo da non bloccare la pipeline di Microsoft Media Foundation. Chiamare MFPutWorkItem e quindi eseguire i passaggi rimanenti all'interno del callback della coda di lavoro.
Nota
Tenere presente che BeginGetCredentials potrebbe essere richiamato durante la creazione dell'origine di rete. Pertanto, se si crea l'origine di rete chiamando il metodo FMSourceResolver::CreateObjectFromURL , il thread chiamante potrebbe bloccare mentre vengono acquisite le credenziali. Pertanto, è consigliabile usare il metodo FMSourceResolver::BeginCreateObjectFromURL .
Esempio
Questo esempio mostra un tipo di comportamento che potrebbe essere fornito da un gestore credenziali.
Ecco una dichiarazione della classe che implementa IMFNetCredentialManager.
class CCredentialManager : public IMFNetCredentialManager, IMFAsyncCallback
{
long m_cRef;
IMFNetCredentialCache *m_pCredentialCache;
public:
CCredentialManager () : m_cRef(1), m_pCredentialCache(NULL)
{
}
~CCredentialManager()
{
SafeRelease(&m_pCredentialCache);
}
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
static const QITAB qit[] =
{
QITABENT(CCredentialManager, IMFNetCredentialManager),
QITABENT(CCredentialManager, IMFAsyncCallback),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) Release()
{
LONG cRef = InterlockedDecrement(&m_cRef);
if (cRef == 0)
{
delete this;
}
return cRef;
}
STDMETHODIMP BeginGetCredentials(
MFNetCredentialManagerGetParam* pParam,
IMFAsyncCallback* pCallback,
IUnknown* pState
);
STDMETHODIMP EndGetCredentials(
IMFAsyncResult* pResult,
IMFNetCredential** ppCred);
STDMETHODIMP SetGood(IMFNetCredential* pCred, BOOL fGood)
{
if (!pCred)
{
return E_POINTER;
}
return m_pCredentialCache->SetGood(pCred, fGood);
}
STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
return E_NOTIMPL;
}
STDMETHODIMP Invoke(IMFAsyncResult* pResult);
};
Per tenere traccia dello stato dell'operazione BeginGetCredentials , la classe usa l'oggetto helper seguente:
// Holds state information for the GetCredentials operation, so that work can
// be moved to a work-queue thread.
struct CredentialOp : public IUnknown
{
long m_cRef;
IMFNetCredential *m_pCredential;
DWORD m_dwFlags;
CredentialOp(IMFNetCredential *pCredential)
: m_cRef(1), m_dwFlags(0), m_pCredential(pCredential)
{
m_pCredential->AddRef();
}
~CredentialOp()
{
SafeRelease(&m_pCredential);
}
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
static const QITAB qit[] =
{
QITABENT(CredentialOp, IUnknown),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) Release()
{
LONG cRef = InterlockedDecrement(&m_cRef);
if (cRef == 0)
{
delete this;
}
return cRef;
}
};
Il metodo BeginGetCredentials crea la cache delle credenziali e ottiene un puntatore FMNetCredential . Se l'utente deve essere richiesto (indicato dal flag di REQUIRE_PROMPT ), il metodo chiama MFPutWorkItem per accodare un nuovo elemento di lavoro:
STDMETHODIMP CCredentialManager::BeginGetCredentials(
MFNetCredentialManagerGetParam* pParam,
IMFAsyncCallback* pCallback,
IUnknown* pState
)
{
if (!pParam || !pCallback)
{
return E_POINTER;
}
DWORD dwAuthenticationFlags = 0;
DWORD dwRequirementFlags = 0;
if (pParam->hrOp == NS_E_PROXY_ACCESSDENIED)
{
dwAuthenticationFlags |= MFNET_AUTHENTICATION_PROXY;
}
if (pParam->fAllowLoggedOnUser)
{
dwAuthenticationFlags |= MFNET_AUTHENTICATION_LOGGED_ON_USER;
}
if (pParam->fClearTextPackage)
{
dwAuthenticationFlags |= MFNET_AUTHENTICATION_CLEAR_TEXT;
}
IMFNetCredential *pCredential = NULL;
IMFAsyncResult* pResult = NULL;
HRESULT hr = S_OK;
if (m_pCredentialCache == NULL)
{
hr = MFCreateCredentialCache(&m_pCredentialCache);
if (FAILED(hr))
{
goto done;
}
}
hr = m_pCredentialCache->GetCredential(
pParam->pszUrl,
pParam->pszRealm,
dwAuthenticationFlags,
&pCredential,
&dwRequirementFlags
);
if (FAILED(hr))
{
goto done;
}
if( ( dwRequirementFlags & REQUIRE_PROMPT ) == 0 )
{
// The credential is good to use. Prompting the user is not required.
hr = S_OK;
goto done;
}
// The credential requires prompting the user.
CredentialOp *pOp = new (std::nothrow) CredentialOp(pCredential);
if (pOp == NULL)
{
hr = E_OUTOFMEMORY;
goto done;
}
// Set flags. Use these to inform the user if the credentials will
// be sent in plaintext or saved in the credential cache.
if (pParam->fClearTextPackage)
{
// Notify the user that credentials will be sent in plaintext.
pOp->m_dwFlags |= MFNET_CREDENTIAL_ALLOW_CLEAR_TEXT;
}
if(dwRequirementFlags & REQUIRE_SAVE_SELECTED )
{
// Credentials will be saved in the cache by default.
pOp->m_dwFlags |= MFNET_CREDENTIAL_SAVE;
}
// NOTE: The application should enable to user to deselect these two flags;
// for example, through check boxes in the prompt dialog.
// Now queue the work item.
hr = MFCreateAsyncResult(pOp, pCallback, pState, &pResult);
if (FAILED(hr))
{
goto done;
}
hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION, this, pResult);
done:
SafeRelease(&pResult);
SafeRelease(&pCredential);
SafeRelease(&pOp);
return hr;
}
Il thread della coda di lavoro chiama Invoke, che richiede all'utente e quindi chiama MFInvokeCallback per richiamare il puntatore di callback fornito in BeginGetCredentials.
STDMETHODIMP CCredentialManager::Invoke(IMFAsyncResult* pResult)
{
IUnknown *pState = NULL;
IMFAsyncResult *pGetCredentialsResult = NULL;
IUnknown *pOpState = NULL;
CredentialOp *pOp = NULL; // not AddRef'd
HRESULT hr = pResult->GetState(&pState);
if (SUCCEEDED(hr))
{
hr = pState->QueryInterface(IID_PPV_ARGS(&pGetCredentialsResult));
}
if (SUCCEEDED(hr))
{
hr = pGetCredentialsResult->GetObject(&pOpState);
}
if (SUCCEEDED(hr))
{
pOp = static_cast<CredentialOp*>(pOpState);
// Display a dialog for the user to enter user name and password.
hr = PromptUserCredentials(pOp);
}
if (SUCCEEDED(hr) && m_pCredentialCache)
{
// Update with options set by the user.
hr = m_pCredentialCache->SetUserOptions(
pOp->m_pCredential,
pOp->m_dwFlags
);
}
if (pGetCredentialsResult)
{
pGetCredentialsResult->SetStatus(hr);
MFInvokeCallback(pGetCredentialsResult);
}
SafeRelease(&pState);
SafeRelease(&pGetCredentialsResult);
SafeRelease(&pOpState);
return S_OK;
}
Il metodo EndGetCredentials completa l'operazione restituendo il puntatore IMFNetCredential al chiamante.
STDMETHODIMP CCredentialManager::EndGetCredentials(
IMFAsyncResult* pResult,
IMFNetCredential** ppCred
)
{
if (!pResult || !ppCred)
{
return E_POINTER;
}
*ppCred = NULL;
IUnknown *pUnk = NULL;
// Check the result of the asynchronous operation.
HRESULT hr = pResult->GetStatus();
if (FAILED(hr))
{
// The operation failed.
goto done;
}
hr = pResult->GetObject(&pUnk);
if (FAILED(hr))
{
goto done;
}
CredentialOp *pOp = static_cast<CredentialOp*>(pUnk);
*ppCred = pOp->m_pCredential;
pOp->m_pCredential = NULL;
done:
SafeRelease(&pUnk);
return hr;
}
Argomenti correlati