ASP.NET Web API: วิธีที่ถูกต้องในการส่งคืนการตอบกลับ 401 / ไม่ได้รับอนุญาต


107

ฉันมีเว็บไซต์ MVC ที่ใช้การตรวจสอบสิทธิ์ OAuth / โทเค็นเพื่อตรวจสอบสิทธิ์คำขอ ตัวควบคุมที่เกี่ยวข้องทั้งหมดมีคุณสมบัติที่ถูกต้องและการตรวจสอบความถูกต้องก็ใช้ได้

ปัญหาคือไม่ใช่ทุกคำขอที่สามารถได้รับอนุญาตในขอบเขตของแอตทริบิวต์ - การตรวจสอบการอนุญาตบางอย่างจะต้องดำเนินการในรหัสที่เรียกโดยวิธีการควบคุม - วิธีที่ถูกต้องในการส่งคืนการตอบกลับที่ไม่ได้รับอนุญาต 401 ในกรณีนี้คืออะไร?

ฉันได้ลองthrow new HttpException(401, "Unauthorized access");แล้ว แต่เมื่อฉันทำสิ่งนี้รหัสสถานะการตอบกลับคือ 500 และฉันก็ได้รับสแต็กแทร็กด้วย แม้แต่ใน DelegatingHandler ในการบันทึกของเราเราจะเห็นว่าการตอบสนองคือ 500 ไม่ใช่ 401


3
ให้กับทุกคนที่หยิบขึ้นมาคำตอบนี้ลงเส้นผมขอแนะนำความคิดเกี่ยวกับเวลาที่เหมาะสมที่จะโยนเมื่อเทียบกับเมื่อมีการส่งกลับHttpResponseException Unauthorized()การใช้ข้อยกเว้นสำหรับข้อผิดพลาด 'คาดว่า' เป็นการต่อต้านรูปแบบเล็กน้อยดังนั้นหากมีบางกรณีที่คุณคาดว่าการโทรจะทำผิดพลาดการส่งกลับUnauthorized()อาจเป็นการโทรที่ถูกต้อง บันทึกHttpResponseExceptionสำหรับสิ่งที่ไม่คาดคิดอย่างแท้จริง
Rikki

ดูgithub.com/aspnet/Mvc/issues/5507สำหรับการสนทนา
Rikki

@Rikki, 401 ไม่ใช่ข้อผิดพลาดที่ "คาดไว้" - เป็นสถานการณ์พิเศษที่ควรทำให้คุณยกเลิกเวิร์กโฟลว์ของคุณ (ยกเว้นอาจเป็นการบันทึกซึ่งคุณควรทำอยู่แล้วสำหรับข้อยกเว้นใด ๆ ... ) - อย่างไรก็ตามหากคุณต้องการส่งคืนผลลัพธ์ที่พิมพ์อย่างชัดเจนจากคอนโทรลเลอร์ของคุณ ( เช่นเพื่อความสะดวกในการทดสอบหน่วย) ข้อยกเว้นเป็นเส้นทางที่ดีที่สุดอย่างชัดเจน
BrainSlugs83

คำตอบ:


148

คุณควรใช้HttpResponseExceptionวิธี API ของคุณไม่ใช่HttpException:

throw new HttpResponseException(HttpStatusCode.Unauthorized);

หรือหากคุณต้องการส่งข้อความที่กำหนดเอง:

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

104

เพียงส่งคืนสิ่งต่อไปนี้:

return Unauthorized();

3
ฉันคิดว่าคำตอบที่ได้รับการยอมรับนั้นตอบคำถามของ OP โดยเฉพาะ คำตอบของฉันตอบหัวข้อคำถาม "ASP.NET Web API: วิธีที่ถูกต้องในการส่งคืนคำตอบ 401 / ไม่ได้รับอนุญาต"
JohnWrensby

3
มีใครรู้บ้างว่าทำไมไม่มีข้อความรุ่นนี้มากเกินไป?
Simon_Weaver

5
@Simon_Weaver ไม่รู้ว่าทำไม แต่คุณสามารถใช้ a return Content<string>(HttpStatusCode.Unauthorized, "Message");เพื่อทำสิ่งนี้ได้
Rikki

2
นี่น่าจะเป็นคำตอบที่ถูกต้อง 1 ถูกต้อง 2) หากสิ่งนี้เปลี่ยนแปลงในกรอบงานในภายหลังคุณไม่จำเป็นต้องเปลี่ยนรหัส 3) คุณไม่จำเป็นต้องให้เหตุผลกับ 401 สิ่งนี้ควรได้รับการจัดการโดยไคลเอนต์ไม่ใช่เซิร์ฟเวอร์
Nick Turner

1
ห้องสมุดนี้อยู่ในห้องสมุดใด
Nae

24

แทนคำตอบอื่น ๆ คุณยังสามารถใช้รหัสนี้หากคุณต้องการส่งคืนIActionResultภายในตัวควบคุม ASP.NET

ASP.NET

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

อัปเดต: ASP.NET Core

โค้ดด้านบนใช้ไม่ได้ใน ASP.NET Core คุณสามารถใช้อย่างใดอย่างหนึ่งต่อไปนี้แทน:

 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");

เห็นได้ชัดว่าวลีเหตุผลนั้นค่อนข้างเป็นทางเลือก ( การตอบสนอง HTTP สามารถละเว้น Reason-Phrase ได้หรือไม่? )


1
สิ่งนี้ใช้ไม่ได้อีกต่อไปใน ASP.NET Core ControllerBaseคลาส (ใช้โดย ASP.NET Core WebAPI) ไม่มีContentโอเวอร์โหลดที่ยอมรับรหัสสถานะ HTTP อีกต่อไป
ได๋

นี่เป็นสิ่งที่ไม่ถูกต้อง การตอบกลับเนื้อหาเป็นสถานะ 200 Ok เซิร์ฟเวอร์ควรส่ง 401 และไคลเอนต์ควรจัดการตามนั้น คุณไม่สามารถส่ง 200 เป็น 401 ได้มันไม่สมเหตุสมผล หากลูกค้าได้รับ 401 ไม่ใช่อ๊ะถือว่าคุณทำผิดกฎหมาย
Nick Turner

รหัสนี้กำลังส่งรหัสสถานะ 401 ( HttpStatusCode.Unauthorized) ไม่ใช่ 200 Content(...)เป็นเพียงชวเลขสำหรับส่งคืนเนื้อหาใด ๆ ที่ระบุด้วยรหัสสถานะ HTTP ที่กำหนด ถ้าคุณต้องการส่ง 200 คุณสามารถใช้ได้Ok(...)
Alex AIT

@NickTurner - นั่นคืออาร์กิวเมนต์สำหรับเมธอด webapi2 Content () ที่มีชื่อไม่ดีไม่ใช่เพราะเป็นคำตอบที่ผิด เนื่องจากเมธอด (สถานะข้อความ) ถูกเปลี่ยนชื่อใน NetCore ฉันเดาว่าผู้พัฒนายอมรับว่ามันตั้งชื่อไม่ดี
Chris F Carroll

9

คุณได้รับรหัสตอบกลับ 500 เนื่องจากคุณกำลังส่งข้อยกเว้น (the HttpException) ซึ่งบ่งบอกถึงข้อผิดพลาดบางอย่างของเซิร์ฟเวอร์ซึ่งเป็นแนวทางที่ไม่ถูกต้อง

เพียงตั้งรหัสสถานะการตอบกลับ. e

Response.StatusCode = (int)HttpStatusCode.Unauthorized;

เป็นเรื่องแปลกเล็กน้อยที่ข้อยกเว้นใช้รหัสสถานะ HTTP เป็นพารามิเตอร์และเอกสาร intellisense บอกว่านี่คือรหัสสถานะที่ส่งไปยังไคลเอนต์ - ฉันหวังว่าจะหลีกเลี่ยงการกลายพันธุ์การตอบสนองด้วยตัวเองโดยตรงเนื่องจากดูเหมือนว่าจะเกิดข้อผิดพลาดได้ง่าย สถานะทั่วโลก
GoatInTheMachine

1
ตัวควบคุม Web API พื้นฐานไม่เปิดเผยResponseคุณสมบัติ
LukeH

3

ในการเพิ่มคำตอบที่มีอยู่ใน ASP.NET Core> = 1.0 คุณสามารถทำได้

return Unauthorized();

return Unauthorized(object value);

ในการส่งข้อมูลไปยังลูกค้าคุณสามารถโทรได้ดังนี้:

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

บนไคลเอนต์นอกเหนือจากการตอบสนอง 401 คุณจะมีข้อมูลที่ส่งผ่านไปด้วย ตัวอย่างเช่นลูกค้าส่วนใหญ่คุณสามารถawait response.json()รับได้


2

ใน. Net Core คุณสามารถใช้ไฟล์

return new ForbidResult();

แทน

return Unauthorized();

ซึ่งมีข้อดีในการเปลี่ยนเส้นทางไปยังเพจที่ไม่ได้รับอนุญาตเริ่มต้น (บัญชี / AccessDenied) แทนที่จะให้ 401 ตรงๆ

ในการเปลี่ยนตำแหน่งเริ่มต้นให้แก้ไข startup.cs ของคุณ

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

            })

คำถามเกี่ยวกับ Web API ดังนั้นนี่จะเป็นคำตอบที่ไม่ถูกต้องถ้าฉันไม่ผิด? API ไม่ควรส่งคืน "การกระทำ" เพียงผลลัพธ์
Niels Lucas

403 เป็นสิ่งต้องห้ามไม่ใช่ 401 ไม่ได้รับอนุญาต มีคำอธิบายที่ดีเกี่ยวกับความแตกต่างที่นี่
อังคาร

1

คุณสามารถใช้รหัสติดตามใน asp.net core 2.0:

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

1

คุณทำตามรหัสนี้ด้วย:

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

คุณไม่จำเป็นต้องตั้งค่า StatusCode อีกครั้งหากคุณส่งต่อไปยังตัวสร้าง - การใช้อย่างใดอย่างหนึ่งก็ดี
Jon Story
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.