實作 IMFNetCredentialManager
在 IMFNetCredentialManager::BeginGetCredentials 方法中,執行下列動作。
- 如果您還沒有 IMFNetCredentialCache 指標,請呼叫 MFCreateCredentialCache 來建立認證快取物件。 儲存此指標。
- 呼叫 IMFNetCredentialCache::GetCredential。 設定 dwAuthenticationFlags 參數中的旗標,如下所示:
- 如果MFNetCredentialManagerGetParam結構的hrOp成員等於NS_E_PROXY_ACCESSDENIED,請設定MFNET_AUTHENTICATION_PROXY旗標。
- 如果 fClearTextPackage 為 TRUE,請設定 MFNET_AUTHENTICATION_CLEAR_TEXT 旗標。
- 如果 fAllowLoggedOnUser 為 TRUE,請設定 MFNET_AUTHENTICATION_LOGGED_ON_USER 旗標。
- GetCredential方法會傳回IMFNetCredential指標,而且可能是REQUIRE_PROMPT旗標。 儲存 IMFNetCredential 指標。
- 如果 GetCredential 未傳回 REQUIRE_PROMPT 旗標,您就會完成。 跳至步驟 9。
- 否則,如果 GetCredential 傳回 REQUIRE_PROMPT 旗標,您必須提示使用者輸入其使用者名稱和密碼。
- 如果 fClearTextPackage 為 FALSE,請加密認證。
- 呼叫 IMFNetCredential::SetUser 和 IMFNetCredential::SetPassword ,在認證物件上設定使用者的名稱和密碼。
- 您可以選擇性地呼叫 IMFNetCredentialCache::SetUserOptions ,以使用使用者的儲存和傳送認證喜好設定來更新認證快取物件。
- 呼叫MFInvokeCallback來叫用IMFAsyncCallback回呼。
在IMFNetCredentialManager::EndGetCredentials方法中,傳回BeginGetCredentials方法中取得的IMFNetCredential指標。
在 IMFNetCredentialManager::SetGood 方法中,將輸入參數直接傳遞至 IMFNetCredentialCache::SetGood 方法。 這會通知認證快取伺服器是否接受認證。
如果您需要提示使用者 (步驟 5) 或加密認證, (步驟 6) ,您應該在工作佇列執行緒上執行此動作,以免封鎖 Microsoft Media Foundation 管線。 呼叫 MFPutWorkItem ,然後在工作佇列回呼內執行其餘步驟。
注意
請注意,在建立網路來源時,可能會叫用 BeginGetCredentials 。 因此,如果您藉由呼叫同步 的 IMFSourceResolver::CreateObjectFromURL 方法來建立網路來源,則呼叫執行緒可能會在取得認證時封鎖。 因此,建議您改用非同步 的 IMFSourceResolver::BeginCreateObjectFromURL 方法。
範例
此範例顯示認證管理員可以提供的一種行為類型。
以下是實作 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);
};
若要追蹤 BeginGetCredentials 作業的狀態,類別會使用下列協助程式物件:
// 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;
}
};
BeginGetCredentials方法會建立認證快取,並取得IMFNetCredential指標。 如果必須提示使用者 (REQUIRE_PROMPT旗標) 表示,此方法會呼叫 MFPutWorkItem 來排入新的工作專案佇列:
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;
}
工作佇列執行緒會呼叫 Invoke,以提示使用者,然後呼叫 MFInvokeCallback 來叫用 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;
}
EndGetCredentials方法會藉由將IMFNetCredential指標傳回給呼叫端來完成作業。
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;
}
相關主題