ASP.NET Web API: 401 / yetkisiz yanıt döndürmenin doğru yolu


103

İsteklerin kimliğini doğrulamak için OAuth / belirteç kimlik doğrulamasını kullanan bir MVC webapi sitem var. İlgili tüm denetleyiciler doğru özniteliklere sahiptir ve kimlik doğrulama sorunsuz çalışıyor.

Sorun, tüm talebin bir öznitelik kapsamında yetkilendirilememesidir - bazı yetkilendirme kontrollerinin, denetleyici yöntemleri tarafından çağrılan kodda gerçekleştirilmesi gerekir - bu durumda 401 yetkisiz yanıtı döndürmenin doğru yolu nedir?

Denedim throw new HttpException(401, "Unauthorized access");, ancak bunu yaptığımda yanıt durum kodu 500 ve ayrıca bir yığın izleme alıyorum. DelegatingHandler günlüğümüzde bile yanıtın 401 değil 500 olduğunu görebiliriz.


2
Bu cevabı satırın aşağısına alan herkese, bir atma zamanı ile HttpResponseExceptionbir Unauthorized(). 'Beklenen' bir hata için istisnayı kullanmak biraz anti-modeldir, bu nedenle, aramanın bu hatayı yapmasını beklediğiniz durumlar varsa, geri dönmek Unauthorized()muhtemelen doğru aramadır. Kaydet HttpResponseExceptiongerçekten beklenmedik için.
Rikki


@Rikki, 401 "beklenen" bir hata değil. - Bu, iş akışınızı iptal etmenize neden olması gereken istisnai bir durumdur (herhangi bir istisna için zaten yapmanız gereken günlük kaydı hariç ...) - Her neyse, denetleyicinizden güçlü bir yazılı sonuç döndürmek istiyorsanız ( Örneğin, ünite testinin kolaylığı için), bir İstisna açıkça en iyi yoldur.
BrainSlugs83

Yanıtlar:


145

Aşağıdakilere HttpResponseExceptiondeğil, API yönteminizden bir atmanız gerekir HttpException:

throw new HttpResponseException(HttpStatusCode.Unauthorized);

Veya, özel bir mesaj sağlamak istiyorsanız:

var msg = new HttpResponseMessage(HttpStatusCode.Unauthorized) { ReasonPhrase = "Oops!!!" };
throw new HttpResponseException(msg);

102

Aşağıdakileri iade etmeniz yeterlidir:

return Unauthorized();

3
Bence kabul edilen, OP'nin sorusuna özellikle cevap veriyor. Cevabım sorunun "ASP.NET Web API: 401 / yetkisiz yanıt döndürmenin doğru yolu"
başlığını yanıtlıyor

3
Bunun neden bir mesajla aşırı yüklenmiş versiyonu olmadığını bilen var mı?
Simon_Weaver

5
@Simon_Weaver Neden bilmiyorum ama bunu return Content<string>(HttpStatusCode.Unauthorized, "Message");yapmak için a kullanabilirsiniz .
Rikki

2
Bu doğru cevap olmalı. 1 doğru. 2) Bu daha sonraki bir çerçevede değişirse, kodu değiştirmeniz gerekmez. 3) 401 için bir neden belirtmenize gerek yoktur. Bu, sunucu tarafından değil, istemci tarafından ele alınmalıdır.
Nick Turner

1
Bu hangi kütüphanede?
Nae

21

Diğer yanıtlara alternatif olarak, IActionResultbir ASP.NET denetleyicisi içinde döndürmek istiyorsanız bu kodu da kullanabilirsiniz .

ASP.NET

 return Content(HttpStatusCode.Unauthorized, "My error message");

Güncelleştirme: ASP.NET Core

Yukarıdaki kod ASP.NET Core'da çalışmaz, bunun yerine bunlardan birini kullanabilirsiniz:

 return StatusCode((int)System.Net.HttpStatusCode.Unauthorized, "My error message");
 return StatusCode(Microsoft.AspNetCore.Http.StatusCodes.Status401Unauthorized, "My error message");
 return StatusCode(401, "My error message");

Görünüşe göre neden ifadesi oldukça isteğe bağlıdır ( Bir HTTP yanıtı, Neden İfadesini çıkarabilir mi? )


1
Bu artık ControllerBaseASP.NET Core'da çalışmaz , sınıf (ASP.NET Core WebAPI tarafından kullanılır) artık ContentHTTP durum kodunu kabul eden bir aşırı yüklemeye sahip değildir.
Dai

Bu yanlış. İçerik yanıtı, 200 Ok durumudur. Sunucu bir 401 göndermeli ve istemci buna göre işlem yapmalıdır. Bir 200'ü 401 olarak gönderemezsiniz. Mantıklı değil. Müşteri 401 alırsa, bu bir Hata değil, kanunu çiğnemenizdir.
Nick Turner

Bu kod, HttpStatusCode.Unauthorized200 değil, 401 durum kodu ( ) gönderiyor. Content(...)Basitçe, belirli bir HTTP durum kodu ile herhangi bir içeriği döndürmek için bir kısaltma. 200 göndermek istiyorsanız kullanabilirsinizOk(...)
Alex AIT

@NickTurner - bu, webapi2 Content () yönteminin yanlış bir cevap olmadığı için kötü isimlendirilmesi için bir argümandır. (Status, message) yöntemi NetCore'da yeniden adlandırıldığından, geliştiricilerin kötü bir şekilde adlandırıldığını kabul ettiğini tahmin ediyorum.
Chris F Carroll

9

500 yanıt kodu alırsınız çünkü bir HttpExceptiontür sunucu hatasını gösteren bir istisna (the ) atarsınız, bu yanlış yaklaşımdır.

Sadece yanıt durum kodunu ayarlayın .eg

Response.StatusCode = (int)HttpStatusCode.Unauthorized;

Bu durumda, istisnanın HTTP durum kodunu bir parametre olarak alması ve intellisense belgelerinin bunun istemciye gönderilen durum kodu olduğunu söylemesi biraz garip - bu, hataya açık göründüğü için yanıtı doğrudan kendim değiştirmekten kaçınmayı umuyordum. küresel durumu
GoatInTheMachine

1
Temel Web API denetleyicisi bir Responseözelliği göstermez.
LukeH

3

ASP.NET Core> = 1.0'daki mevcut bir yanıta eklemek için şunları yapabilirsiniz:

return Unauthorized();

return Unauthorized(object value);

Müşteriye bilgi iletmek için aşağıdaki gibi bir arama yapabilirsiniz:

return Unauthorized(new { Ok = false, Code = Constants.INVALID_CREDENTIALS, ...});

İstemcide 401 yanıtının yanı sıra aktarılan verilere de sahip olacaksınız. Örneğin, çoğu müşteride bunu elde edebilirsiniz await response.json().


3

NET Core'da kullanabilirsiniz

return new ForbidResult();

onun yerine

return Unauthorized();

Doğrudan bir 401 vermek yerine varsayılan yetkisiz sayfaya (Hesap / Erişim Reddedildi) yönlendirme avantajı vardır.

varsayılan konumu değiştirmek için startup.cs dosyanızı değiştirin

services.AddAuthentication(options =>...)
            .AddOpenIdConnect(options =>...)
            .AddCookie(options =>
            {
                options.AccessDeniedPath = "/path/unauthorized";

            })

Soru, bir web API ile ilgili. Yani yanılmıyorsam bu geçersiz bir cevap mı olur? API 'eylemler' döndürmemeli, yalnızca sonuçlar döndürmelidir.
Niels Lucas

1

asp.net core 2.0'da aşağıdaki kodu kullanabilirsiniz:

public IActionResult index()
{
     return new ContentResult() { Content = "My error message", StatusCode = (int)HttpStatusCode.Unauthorized };
}

1

Ayrıca şu kodu da takip edersiniz:

var response = new HttpResponseMessage(HttpStatusCode.NotFound)
{
      Content = new StringContent("Users doesn't exist", System.Text.Encoding.UTF8, "text/plain"),
      StatusCode = HttpStatusCode.NotFound
 }
 throw new HttpResponseException(response);

Yapıcıya iletirseniz Durum Kodunu tekrar ayarlamanıza gerek yoktur - ikisinden birini kullanmak iyidir
Jon Story
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.