Bagikan melalui


Menerapkan IMFNetCredentialManager

Dalam metode IMFNetCredentialManager::BeginGetCredentials , lakukan hal berikut.

  1. Jika Anda belum memiliki penunjuk IMFNetCredentialCache , panggil MFCreateCredentialCache untuk membuat objek cache kredensial. Simpan pointer ini.
  2. Panggil IMFNetCredentialCache::GetCredential. Atur bendera dalam parameter dwAuthenticationFlags sebagai berikut:
    • Jika anggota hrOp dari struktur MFNetCredentialManagerGetParam sama dengan NS_E_PROXY_ACCESSDENIED, atur bendera MFNET_AUTHENTICATION_PROXY .
    • Jika fClearTextPackageTRUE, atur bendera MFNET_AUTHENTICATION_CLEAR_TEXT .
    • Jika fAllowLoggedOnUserTRUE, atur bendera MFNET_AUTHENTICATION_LOGGED_ON_USER .
  3. Metode GetCredential mengembalikan penunjuk IMFNetCredential dan mungkin bendera REQUIRE_PROMPT. Simpan penunjuk IMFNetCredential .
  4. Jika GetCredential tidak mengembalikan bendera REQUIRE_PROMPT , Anda selesai. Lewati ke langkah 9.
  5. Jika tidak, jika GetCredential mengembalikan bendera REQUIRE_PROMPT , Anda harus meminta nama pengguna dan kata sandinya kepada pengguna.
  6. Jika fClearTextPackageFALSE, enkripsi kredensial.
  7. Panggil IMFNetCredential::SetUser dan IMFNetCredential::SetPassword untuk mengatur nama dan kata sandi pengguna pada objek kredensial.
  8. Secara opsional, panggil IMFNetCredentialCache::SetUserOptions untuk memperbarui objek cache kredensial dengan preferensi pengguna untuk menyimpan dan mengirim kredensial.
  9. Panggil panggilan balik IMFAsyncCallback dengan memanggil MFInvokeCallback.

Dalam metode IMFNetCredentialManager::EndGetCredentials , kembalikan penunjuk IMFNetCredential yang diperoleh dalam metode BeginGetCredentials .

Dalam metode IMFNetCredentialManager::SetGood , teruskan parameter input langsung ke metode IMFNetCredentialCache::SetGood . Ini memberi tahu cache kredensial apakah kredensial diterima oleh server.

Jika Anda perlu meminta pengguna (langkah 5) atau mengenkripsi kredensial (langkah 6), Anda harus melakukannya pada utas antrean kerja, sehingga Anda tidak memblokir alur Microsoft Media Foundation. Panggil MFPutWorkItem lalu lakukan langkah-langkah yang tersisa di dalam panggilan balik antrean kerja.

Catatan

Ketahuilah bahwa BeginGetCredentials mungkin dipanggil saat sumber jaringan sedang dibuat. Oleh karena itu, jika Anda membuat sumber jaringan dengan memanggil metode IMFSourceResolver::CreateObjectFromURL sinkron, alur panggilan Anda mungkin memblokir saat kredensial diperoleh. Oleh karena itu, disarankan untuk menggunakan metode IMFSourceResolver asinkron::BeginCreateObjectFromURL sebagai gantinya.

 

Contoh

Contoh ini menunjukkan satu jenis perilaku yang dapat diberikan oleh manajer kredensial.

Berikut adalah deklarasi kelas yang mengimplementasikan 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);
};

Untuk melacak status operasi BeginGetCredentials , kelas menggunakan objek pembantu berikut:

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

Metode BeginGetCredentials membuat cache kredensial dan mendapatkan penunjuk IMFNetCredential . Jika pengguna harus diminta (ditunjukkan oleh bendera REQUIRE_PROMPT ), metode memanggil MFPutWorkItem untuk mengantre item kerja baru:

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

Utas antrean kerja memanggil Invoke, yang meminta pengguna lalu memanggil MFInvokeCallback untuk memanggil penunjuk panggilan balik yang disediakan di 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;
}

Metode EndGetCredentials menyelesaikan operasi dengan mengembalikan penunjuk IMFNetCredential ke pemanggil.

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

Autentikasi Sumber Jaringan