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단계로 건너뛰세요.
- 그렇지 않으면 GetCredentialREQUIRE_PROMPT 플래그를 반환하는 경우 사용자에게 사용자 이름과 암호를 묻는 메시지를 표시해야 합니다.
- fClearTextPackage이 FALSE인 경우, 자격 증명을 암호화합니다.
- IMFNetCredential::SetUser 호출하고 IMFNetCredential::SetPassword자격 증명 개체에서 사용자의 이름과 암호를 설정합니다.
- 필요에 따라 IMFNetCredentialCache::SetUserOptions 호출하여 자격 증명을 저장하고 보내기 위한 사용자의 기본 설정으로 자격 증명 캐시 개체를 업데이트합니다.
- MFInvokeCallback를 호출하여 IMFAsyncCallback 콜백을 실행합니다.
IMFNetCredentialManager::EndGetCredentials 메서드에서 BeginGetCredentials 메서드에서 가져온 IMFNetCredential 포인터를 반환합니다.
IMFNetCredentialManager::SetGood 메서드에서 입력 매개 변수를 IMFNetCredentialCache::SetGood 메서드에 직접 전달합니다. 이렇게 하면 자격 증명이 서버에서 수락되었는지 여부를 자격 증명 캐시에 알릴 수 있습니다.
사용자에게 메시지를 표시하거나 자격 증명(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;
}
작업 큐 스레드는 호출호출합니다. 그러면 사용자에게 메시지를 표시한 다음 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;
}
관련 항목