Bagikan melalui


Tentukan kredensial autentikasi server untuk pekerjaan transfer BITS

Anda dapat menentukan skema autentikasi yang berbeda untuk pekerjaan transfer Background Intelligent Transfer Service (BITS).

Prosedur berikut mendapatkan skema autentikasi dan membuat struktur identitas autentikasi. Kemudian aplikasi membuat pekerjaan pengunduhan BITS dan mengatur kredensial untuk pekerjaan tersebut. Setelah pekerjaan dibuat, aplikasi mendapatkan pointer ke antarmuka panggilan balik dan jajak pendapat untuk status pekerjaan transfer BITS. Setelah pekerjaan selesai, pekerjaan dihapus dari antrean.

Contoh ini menggunakan header dan implementasi yang ditentukan dalam Contoh: Kelas Umum.

Untuk menentukan kredensial autentikasi server untuk pekerjaan transfer BITS

  1. Buat struktur kontainer yang memetakan nilai BG_AUTH_SCHEME ke nama skema.

    struct
    {
        LPCWSTR        Name;
        BG_AUTH_SCHEME Scheme;
    }
    SchemeNames[] =
    {
        { L"basic",      BG_AUTH_SCHEME_BASIC },
        { L"digest",     BG_AUTH_SCHEME_DIGEST },
        { L"ntlm",       BG_AUTH_SCHEME_NTLM },
        { L"negotiate",  BG_AUTH_SCHEME_NEGOTIATE },
        { L"passport",   BG_AUTH_SCHEME_PASSPORT },
    
        { NULL,         BG_AUTH_SCHEME_BASIC }
    };
    
  2. Inisialisasi parameter COM dengan memanggil fungsi CCoInitializer. Untuk informasi selengkapnya tentang fungsi CCoInitializer, lihat Contoh: Kelas Umum.

  3. Siapkan struktur BG_AUTH_CREDENTIALS . Contoh menggunakan fungsi SecureZeroMemory untuk menghapus lokasi memori yang terkait dengan informasi sensitif. Fungsi SecureZeroMemory didefinisikan dalam WinBase.h.

  4. Gunakan fungsi GetScheme untuk mendapatkan skema autentikasi yang akan digunakan untuk menyambungkan ke server.

    bool GetScheme( LPCWSTR s, BG_AUTH_SCHEME *scheme )
    {
        int i;
    
        i = 0;
        while (SchemeNames[i].Name != NULL)
        {
            if (0 == _wcsicmp( s, SchemeNames[i].Name ))
            {
    
                *scheme = SchemeNames[i].Scheme;
                return true;
            }
    
            ++i;
        }
    
        return false;
    }
    
  5. Isi struktur BG_AUTH_CREDENTIALS dengan skema autentikasi yang dikembalikan oleh fungsi GetScheme dan nama pengguna dan kata sandi yang diteruskan ke fungsi ServerAuthentication.

  6. Dapatkan pointer ke antarmuka IBackgroundCopyJob (pJob).

  7. Menginisialisasi keamanan proses COM dengan memanggil CoInitializeSecurity. BITS memerlukan setidaknya tingkat impersonasi IMPERSONATE. BITS gagal dengan E_ACCESSDENIED jika tingkat peniruan yang benar tidak diatur.

  8. Dapatkan penunjuk ke antarmuka IBackgroundCopyManager , dan dapatkan pencari lokasi awal ke BITS dengan memanggil fungsi CoCreateInstance .

  9. Buat pekerjaan transfer BITS dengan memanggil metode IBackgroundCopyManager::CreateJob.

  10. Dapatkan penunjuk ke antarmuka panggilan balik CNotifyInterface dan panggil metode IBackgroundCopyJob::SetNotifyInterface untuk menerima pemberitahuan peristiwa terkait pekerjaan. Untuk informasi selengkapnya tentang CNotifyInterface, lihat Contoh: Kelas Umum.

  11. Panggil metode IBackgroundCopyJob::SetNotifyFlags untuk mengatur jenis pemberitahuan yang akan diterima. Dalam contoh ini, bendera BG_NOTIFY_JOB_TRANSFERRED dan BG_NOTIFY_JOB_ERROR diatur.

  12. Dapatkan penunjuk ke antarmuka IBackgroundCopyJob2. Gunakan penunjuk IBackgroundCopyJob2 untuk mengatur properti tambahan pada pekerjaan. Program ini menggunakan metode IBackgroundCopyJob2::SetCredentials untuk mengatur kredensial untuk pekerjaan transfer BITS.

  13. Tambahkan file ke pekerjaan transfer BITS dengan memanggil IBackgroundCopyJob::AddFile. Dalam contoh ini, metode IBackgroundCopyJob::AddFile menggunakan variabel remoteFile dan localFile yang diteruskan ke fungsi ServerAuthentication.

  14. Setelah file ditambahkan, panggil IBackgroundCopyJob::Lanjutkan untuk melanjutkan pekerjaan.

  15. Siapkan perulangan sementara untuk menunggu Keluar dari antarmuka panggilan balik saat pekerjaan sedang ditransfer.

    Catatan

    Langkah ini diperlukan hanya jika apartemen COM adalah apartemen berulir tunggal. Untuk informasi selengkapnya, lihat Apartemen Berulir Tunggal.

     

    // Wait for QuitMessage from CallBack
        DWORD dwLimit = GetTickCount() + (15 * 60 * 1000);  // set 15 minute limit
        while (dwLimit > GetTickCount())
        {
            MSG msg;
    
            while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
            { 
                // If it is a quit message, exit.
                if (msg.message == WM_QUIT) 
                {
                    return;
                }
    
                // Otherwise, dispatch the message.
                DispatchMessage(&msg); 
            } // End of PeekMessage while loop
        }
    

    Perulangan sebelumnya menggunakan fungsi GetTickCount untuk mengambil jumlah milidetik yang telah berlalu sejak pekerjaan mulai ditransfer.

  16. Setelah pekerjaan transfer BITS selesai, hapus pekerjaan dari antrean dengan memanggil IBackgroundCopyJob::Complete.

Contoh kode berikut menentukan kredensial autentikasi server untuk pekerjaan transfer BITS.

#include <bits.h>
#include <bits4_0.h>
#include <stdio.h>
#include <tchar.h>
#include <lm.h>
#include <iostream>
#include <exception>
#include <string>
#include <atlbase.h>
#include <memory>
#include <new>
#include "CommonCode.h"

//
// Retrieve BG_AUTH_SCHEME from scheme name.
//
//
struct
{
    LPCWSTR        Name;
    BG_AUTH_SCHEME Scheme;
}
SchemeNames[] =
{
    { L"basic",      BG_AUTH_SCHEME_BASIC },
    { L"digest",     BG_AUTH_SCHEME_DIGEST },
    { L"ntlm",       BG_AUTH_SCHEME_NTLM },
    { L"negotiate",  BG_AUTH_SCHEME_NEGOTIATE },
    { L"passport",   BG_AUTH_SCHEME_PASSPORT },

    { NULL,         BG_AUTH_SCHEME_BASIC }
};

bool GetScheme( LPCWSTR s, BG_AUTH_SCHEME *scheme )
{
    int i;

    i = 0;
    while (SchemeNames[i].Name != NULL)
    {
        if (0 == _wcsicmp( s, SchemeNames[i].Name ))
        {

            *scheme = SchemeNames[i].Scheme;
            return true;
        }

        ++i;
    }

    return false;
}

void ServerAuthentication(const LPWSTR &remoteFile, const LPWSTR &localFile, const LPWSTR &scheme, const LPWSTR &username, const LPWSTR &password)
{

 // If CoInitializeEx fails, the exception is unhandled and the program terminates  
 CCoInitializer coInitializer(COINIT_APARTMENTTHREADED);
    
    // Prepare the credentials structure.
    BG_AUTH_CREDENTIALS cred;
    ZeroMemory(&cred, sizeof(cred));
    if (!GetScheme(scheme,&cred.Scheme))
    {
        wprintf(L"Invalid authentication scheme specified\n");
        return;
    }

    cred.Target = BG_AUTH_TARGET_SERVER;
    cred.Credentials.Basic.UserName = username;
    if (0 == _wcsicmp(cred.Credentials.Basic.UserName, L"NULL"))
    {
        cred.Credentials.Basic.UserName = NULL;
    }

    cred.Credentials.Basic.Password = password;
    if (0 == _wcsicmp(cred.Credentials.Basic.Password, L"NULL"))
    {
        cred.Credentials.Basic.Password = NULL;
    }

    CComPtr<IBackgroundCopyJob> pJob;
    try
    {
        //The impersonation level must be at least RPC_C_IMP_LEVEL_IMPERSONATE.
        HRESULT hr = CoInitializeSecurity(NULL, 
            -1, 
            NULL, 
            NULL,
            RPC_C_AUTHN_LEVEL_CONNECT,
            RPC_C_IMP_LEVEL_IMPERSONATE,
            NULL, 
            EOAC_DYNAMIC_CLOAKING, 
            0);
        if (FAILED(hr))
        {
            throw MyException(hr, L"CoInitializeSecurity");
        }

        // Connect to BITS.
        CComPtr<IBackgroundCopyManager> pQueueMgr;
        hr = CoCreateInstance(__uuidof(BackgroundCopyManager), NULL,
            CLSCTX_LOCAL_SERVER,
            __uuidof(IBackgroundCopyManager),
            (void**)&pQueueMgr);

        if (FAILED(hr))
        {
            // Failed to connect.
            throw MyException(hr, L"CoCreateInstance");
        }

        // Create a job.
        wprintf(L"Creating Job...\n");

        GUID guidJob;
        hr = pQueueMgr->CreateJob(L"BitsAuthSample",
            BG_JOB_TYPE_DOWNLOAD,
            &guidJob,
            &pJob);

        if (FAILED(hr))
        {
            // Failed to connect.
            throw MyException(hr, L"CreateJob");
        }

        // Set the File Completed call.
        CComPtr<CNotifyInterface> pNotify;
        pNotify = new CNotifyInterface();
        hr = pJob->SetNotifyInterface(pNotify);
        if (FAILED(hr))
        {
            // Failed to connect.
            throw MyException(hr, L"SetNotifyInterface");
        }
        hr = pJob->SetNotifyFlags(BG_NOTIFY_JOB_TRANSFERRED | 
            BG_NOTIFY_JOB_ERROR);

        if (FAILED(hr))
        {
            // Failed to connect.
            throw MyException(hr, L"SetNotifyFlags");
        }

        // Set credentials.
        CComPtr<IBackgroundCopyJob2> job2;
        hr = pJob.QueryInterface(&job2);
        if (FAILED(hr))
        {
            // Failed to connect.
            throw MyException(hr, L"QueryInterface");
        }

        hr = job2->SetCredentials(&cred);
        if (FAILED(hr))
        {
            // Failed to connect.
            throw MyException(hr, L"SetCredentials");
        }

        // Add a file.
        wprintf(L"Adding File to Job\n");
        hr = pJob->AddFile(remoteFile, localFile);
        if (FAILED(hr))
        {
            // Failed to connect.
            throw MyException(hr, L"AddFile");
        }

        //Resume the job.
        wprintf(L"Resuming Job...\n");
        hr = pJob->Resume();
        if (FAILED(hr))
        {
            // Failed to connect.
            throw MyException(hr, L"Resume");
        }
    }
    catch(const std::bad_alloc &)
    {
        wprintf(L"Memory allocation failed");
        if (pJob)
        {
            pJob->Cancel();
        }

        return;
    }
    catch(const MyException &ex)
    {
        wprintf(L"Error %x occurred during operation", ex.Error);
        if (pJob)
        {
            pJob->Cancel();
        }

        return;
    }

    wprintf(L"Transferring file and waiting for callback.\n");

    // Wait for QuitMessage from CallBack.
    DWORD dwLimit = GetTickCount() + (15 * 60 * 1000);  // set 15 minute limit
    while (dwLimit > GetTickCount())
    {
        MSG msg;

        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
        { 
            // If it is a quit message, exit.
            if (msg.message == WM_QUIT) 
            {
                return;
            }

            // Otherwise, dispatch the message.
            DispatchMessage(&msg); 
        } // End of PeekMessage while loop
    }

    pJob->Cancel();
    return;
}

void _cdecl _tmain(int argc, LPWSTR* argv)
{   
    if (argc != 6)
    {
        wprintf(L"Usage:");
        wprintf(L"%s", argv[0]);
        wprintf(L" [remote name] [local name] [server authentication scheme =\"NTLM\"|\"NEGOTIATE\"|\"BASIC\"|\"DIGEST\"] [username] [password]\n");
        return;
    }

    ServerAuthentication(argv[1], argv[2], argv[3], argv[4], argv[5]); 

}

IBackgroundCopyManager

IBackgroundCopyJob

IBackgroundCopyJob2

Contoh: Kelas Umum