Panggil API Web dari Aplikasi MVC dengan Otentikasi Windows Terintegrasi

Saya memiliki Aplikasi MVC dan proyek API Web terkait yang keduanya dihosting di server jarak jauh di IIS. Mereka berbagi kumpulan aplikasi yang sama. Setiap kali saya mencoba melakukan panggilan ke Web API dari Aplikasi MVC saya mendapatkan kesalahan 403, yang tampaknya berasal dari kredensial buruk yang diteruskan oleh HttpClientHandler. Saya punya

UseDefaultCredentials = true 

dan saya sudah mencoba pengaturan

Credentials = CredentialCache.DefaultNetworkCredentials

namun tidak satu pun dari hal ini yang mengizinkan permintaan API untuk dilalui.

Menyetel Kumpulan Aplikasi untuk menggunakan Nama Pengguna/Kata Sandi AD saya memungkinkan semua permintaan API diproses, dan juga memanggil API langsung dari Tukang Pos akan mengembalikan data dengan benar.

Asumsi saya adalah IIS AppPool[Pool Name] diteruskan dalam permintaan, dan kredensial yang tepat tidak pernah diteruskan. Apakah ada cara lain untuk mengatasi hal ini tanpa membuat API tidak aman (yaitu hanya beberapa grup domain yang dapat mengaksesnya)?

Contoh panggilan yang saya lakukan ke API dari aplikasi MVC

    public async Task<HttpResponseMessage> CreateIncident(Incident model)
    {
        using (var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }))
        {
            var newIncident = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json");
            var response = await client.PostAsync(hostUri, newIncident);
            return response;
        }
    }

person Robert McCoy    schedule 27.02.2017    source sumber
comment
Apakah Anda menggunakan proxy sama sekali?   -  person joshmcode    schedule 28.02.2017
comment
Tidak, ini semua dihosting di server internal dan semua panggilan dilakukan secara eksklusif melalui server itu. Tidak ada proksi. Seperti yang saya katakan, Tukang Pos dan panggilan langsung ke API dari komputer saya berhasil, tetapi tampaknya .NET Core tidak dapat meniru permintaan tersebut, dan saya berharap orang lain telah melakukan ini baru-baru ini yang dapat memberikan informasi yang lebih terkini. solusi dibandingkan beberapa solusi berusia 6+ bulan yang agak ketinggalan jaman di .NET Core.   -  person Robert McCoy    schedule 28.02.2017


Jawaban (3)


Tanpa informasi lebih lanjut, sulit untuk memastikannya, namun masalahnya mungkin disebabkan oleh otentikasi double-hop yang Anda coba.

  1. aplikasi klien (browser dalam kasus situs web) mengautentikasi pengguna yang dikirim klien
  2. otentikasi ke server (aplikasi MVC)
  3. aplikasi MVC kemudian mencoba meneruskan otentikasi ke layanan web

Ketika saya perlu melakukan tugas serupa, saya tidak dapat membuat HttpClient berfungsi. Saya mencoba sejumlah solusi yang disarankan dari pertanyaan ini, Bagaimana cara agar HttpClient meneruskan kredensial bersama dengan permintaan?. Meskipun bersifat informatif -- khususnya, bagian jawaban BlackSpy ini menjelaskan alasannya:

Apa yang Anda coba lakukan adalah membuat NTLM meneruskan identitas ke server berikutnya, yang tidak dapat dilakukannya - ia hanya dapat melakukan peniruan identitas yang hanya memberi Anda akses ke sumber daya lokal.

Saya akhirnya menggunakan WebClient (dengan penargetan yang diperlukan kerangka .NET) dengan sesuatu seperti ini di aplikasi MVC (mengunduh file dari api web, dalam hal ini):

private async Task GetFileAsync(Identity identity, string serviceAddress, Stream stream)
{
    var windowsIdentity = Identity as WindowsIdentity;

    if (windowsIdentity == null)
    {
        throw new InvalidOperationException("Identity not a valid windows identity.");
    }

    using (windowsIdentity.Impersonate())
    {
        using (var client = new WebClient { UseDefaultCredentials = true })
        {
            var fileData = await client.DownloadDataTaskAsync(serviceAddress);
            await stream.WriteAsync(fileData, 0, fileData.Length);
            stream.Seek(0, SeekOrigin.Begin);
        }
    }
}

Meskipun persyaratan untuk menargetkan kerangka kerja penuh mencegah ini menjadi solusi .NET Core, namun sepertinya solusi tersebut telah ditambahkan sejak saat itu.

Tambahkan WebClient ke kontrak System.Net.WebClient baru

PR ini mem-porting System.Net.WebClient ke corefx. Kode ini sebagian besar diambil dari desktop dan kemudian dibersihkan sedikit secara gaya. Satu-satunya penulisan ulang kode utama adalah menghapus ratusan baris kode berbasis panggilan balik APM yang rumit dan menggantinya dengan beberapa metode asinkron inti. Masih banyak lagi pembersihan yang bisa dilakukan, namun secara fungsional sudah cukup.

person David Culp    schedule 28.02.2017
comment
Saya melihat solusi ini (dan membaca terlalu banyak hal tentang double hop), tapi menurut saya Klien Web belum ada di Core. Mereka menggabungkannya ke dalam repositori, tetapi sejauh yang saya tahu itu tidak pernah disertakan dalam RC atau Pratinjau apa pun, dan saya tidak bisa mereferensikannya di Visual Studio. Saya berharap seseorang akan memiliki implementasi yang lebih terkini untuk peniruan identitas, karena thread Stack Overflow lain yang saya baca memiliki solusi usang yang tidak lagi berfungsi. Saya tidak ingin kembali ke .NET Framework, tetapi hal ini mungkin juga terjadi. Terima kasih! - person Robert McCoy; 28.02.2017
comment
Hai David, saya akhirnya menemukan solusi yang selama ini saya cari (Ya...perlu beberapa saat). Anda dapat menemukan diskusi masalah GitHub di sini, dan pengguna ilanc telah memposting tautan ke contoh cara repo di bagian bawah diskusi. github.com/aspnet/Home/issues/1805 - person Robert McCoy; 02.03.2017

Tanpa melihat kodenya sulit untuk mengatakannya. Sudahkah Anda mencoba tanpa menyetel parameter Credentials? Saya akan menjalankan fiddler dan membandingkan permintaan yang dikirim oleh aplikasi MVC dan Tukang Pos.

person Shane Ray    schedule 27.02.2017
comment
Saya melihat hasil dari Fiddler. Tukang pos bahkan tidak melakukan negosiasi apa pun karena Otentikasi Windows Terintegrasi, server secara otomatis menentukan kredensial login saya. Sedangkan untuk aplikasi MVC, ia mengirimkan Otorisasi Negosiasi dengan permintaan, dan itu mengembalikan 401. Itu sebabnya menurut saya API mendapatkan informasi IIS AppPool dan mengirimkannya sebagai kredensial. Saya juga memberikan sedikit contoh kode pada pertanyaan. - person Robert McCoy; 28.02.2017
comment
Sudahkah Anda mencoba menghapus UseDefaultCredentials = true? - person Shane Ray; 28.02.2017
comment
Ya, sepertinya tidak ada dampak apa pun. Juga mencoba melakukan PreAuth = false dan Kredensial disetel ke sesuatu. Mungkin saja menggunakan solusi David dan aplikasinya tidak sepenuhnya Inti. - person Robert McCoy; 28.02.2017

Anda dapat mengetahui cara meniru identitas pengguna (windows) yang sudah diautentikasi di halaman diskusi GitHub ini: https://github.com/aspnet/Home/issues/1805

ilanc memiliki demo yang sangat bagus dengan tautan di bagian bawah.

person Robert McCoy    schedule 01.03.2017