Menerapkan otentikasi HTTP di Web API

Pada artikel ini saya akan menyajikan diskusi tentang penerapan otentikasi HTTP di Web API. Ada dua cara untuk menerapkan otentikasi HTTP di Api Web Anda. Ini termasuk:

  • Bentuk otentikasi
  • Otentikasi dasar

Kami tidak akan menganggap otentikasi Windows sebagai strategi yang layak karena Anda tidak dapat mengekspos layanan Anda melalui Internet jika Anda memanfaatkan otentikasi Windows.

Mengamankan Api Web menggunakan Otentikasi Formulir

Bentuk otentikasi menggunakan penyedia keanggotaan ASP.Net dan menggunakan cookie HTTP standar, bukan header Otorisasi. Otentikasi formulir tidak ramah REST karena menggunakan cookie, dan klien perlu mengelola cookie untuk menggunakan layanan yang memanfaatkan otentikasi formulir, yang rentan terhadap serangan pemalsuan lintas situs. Inilah sebabnya mengapa Anda perlu menerapkan tindakan CSRF jika Anda menggunakan otentikasi formulir. Otentikasi formulir tidak menggunakan enkripsi untuk mengamankan kredensial pengguna. Karenanya, ini bukan strategi yang aman kecuali Anda menjalankan API Web melalui SSL.

Secure Web API menggunakan otentikasi dasar

Otentikasi dasar mengirimkan kredensial pengguna dalam teks keluhan melalui kabel. Jika Anda akan menggunakan otentikasi dasar, Anda harus menggunakan API Web Anda melalui Secure Socket Layer (SSL). Saat menggunakan otentikasi dasar, kami akan meneruskan kredensial pengguna atau token otentikasi di header permintaan HTTP. Layanan di sisi server perlu mengurai header untuk mengambil token autentikasi. Jika permintaan tersebut bukan permintaan yang valid, server mengembalikan HTTP 401, yang berarti tanggapan yang tidak sah.

Mari jelajahi bagaimana kita dapat melakukan otentikasi dasar menggunakan filter tindakan. Untuk melakukan ini, Anda harus membuat kelas yang menurunkan System.Web.Http.Filters.ActionFilterAttributekelas seperti yang ditunjukkan di bawah ini:

public class BasicAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute

    {

        private Boolean IsUserValid(Dictionary credentials)

        {

            if (credentials["UserName"].Equals("joydip") && credentials["Password"].Equals("joydip123"))

                return true;

            return false;

        }

         private Dictionary ParseRequestHeaders(System.Web.Http.Controllers.HttpActionContext actionContext)

        {

            Dictionary credentials = new Dictionary();

             var httpRequestHeader = actionContext.Request.Headers.GetValues("Authorization").FirstOrDefault();

            httpRequestHeader = httpRequestHeader.Substring("Authorization".Length);

             string[] httpRequestHeaderValues = httpRequestHeader.Split(':');

            string username = Encoding.UTF8.GetString(Convert.FromBase64String(httpRequestHeaderValues[0]));

            string password = Encoding.UTF8.GetString(Convert.FromBase64String(httpRequestHeaderValues[1]));

             credentials.Add("UserName", username);

            credentials.Add("Password", password);

             return credentials;

        }

         public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)

        {

            try

            {

                if (actionContext.Request.Headers.Authorization == null)

                {

                    actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

                }

                else

                {

                     Dictionary credentials = ParseRequestHeaders(actionContext);

                     if (IsUserValid(credentials))

                        actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.OK);

                    else

                        actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

                 }

            }

            catch

            {

                actionContext.Response = new System.Net.Http.HttpResponseMessage

(System.Net.HttpStatusCode.InternalServerError);

            }

        }

    }

Kami memeriksa apakah header otorisasi ada; jika tidak, respons HTTP 401 atau "tidak sah" dikembalikan.

Langkah selanjutnya adalah memvalidasi kredensial pengguna yang diteruskan melalui header permintaan otorisasi dari klien. Sebelum kita melakukan itu, kita harus tahu bagaimana Web API dipanggil dari klien. Untuk ini, saya sudah menyiapkan metode pengujian. Metode pengujian menggunakan HttpClientkelas untuk memanggil API Web. Perhatikan bahwa nama pengguna diubah ke format string Base64 sebelum diteruskan. Metode pengujian diberikan di bawah ini.

[TestMethod]

        public void BasicAuthenticationTest()

        {

            string username = Convert.ToBase64String(Encoding.UTF8.GetBytes("joydip"));

            string password = Convert.ToBase64String(Encoding.UTF8.GetBytes("joydip123"));

            HttpClient client = new HttpClient();

            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", username + ":" + password);

            var result = client.GetAsync(new Uri("//localhost//api/default/")).Result;

           Assert.IsTrue(result.IsSuccessStatusCode);

        }

Seperti yang Anda lihat pada potongan kode di atas, kredensial pengguna diteruskan menggunakan header otorisasi.

Sekarang klien sudah siap, mari selesaikan implementasi BasicAuthenicationFilterkelas. Di dalam OnActionExecutingmetode kita perlu mengurai nilai header di kelas ini dan memeriksa apakah kredensial yang diberikan dari klien cocok. Untuk saat ini, mari kita asumsikan bahwa nama pengguna dan kata sandi memiliki nilai joydipdan joydip123, masing-masing (keduanya dikodekan dengan keras). Berikut kode lengkap BasicAuthenticationFilterkelas yang menggabungkan validasi kredensial pengguna.

public class BasicAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute

    {

        public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)

        {

            try

            {

                if (actionContext.Request.Headers.Authorization == null)

                {

                    actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

                }

                else

                {

                    actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError);

                    var httpRequestHeader = actionContext.Request.Headers.GetValues("Authorization").FirstOrDefault();

                    httpRequestHeader = httpRequestHeader.Substring("Authorization".Length);

                    string[] httpRequestHeaderValues = httpRequestHeader.Split(':');

                    string username = Encoding.UTF8.GetString(Convert.FromBase64String(httpRequestHeaderValues[0]));

                    string password = Encoding.UTF8.GetString(Convert.FromBase64String(httpRequestHeaderValues[1]));

                    if (username.Equals("joydip") && password.Equals("joydip123"))

                        actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.OK);

                    else

                        actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

                }

            }

            catch

            {

                actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError);

            }

        }

    }

Di kelas pengontrol Anda, Anda harus menentukan atribut dengan tepat. Perhatikan bahwa BasicAuthenticationatribut di sini mengacu pada BasicAuthenticationAttributekelas yang kami terapkan.

    [BasicAuthentication]

    public class DefaultController : ApiController

    {

        public IEnumerable Get()

        {

            return new string[] { "Joydip", "Kanjilal" };

        }

    }

Sekarang, sedikit konfigurasi --- Anda perlu mengkonfigurasi atribut sehingga panggilan ke pengontrol Anda akan disaring dengan tepat agar otentikasi bekerja.

 public static class WebApiConfig

    {

        public static void Register(HttpConfiguration config)

        {

            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(

                name: "DefaultApi",

                routeTemplate: "api/{controller}/{id}",

                defaults: new { id = RouteParameter.Optional }

            );

            config.Formatters.Remove(config.Formatters.XmlFormatter);

            GlobalConfiguration.Configuration.Filters.Add(new BasicAuthenticationAttribute());

        }

    }

Dan Anda selesai! Saat Anda menjalankan kasus pengujian, pengujian tersebut berhasil.

Anda tetap harus memastikan bahwa kredensial tidak di-hardcode; sebaliknya, mereka harus disimpan dalam database dan Anda harus mengambilnya dan memvalidasi dalam OnActionExecutingmetode BasicAuthenticationAttributekelas.