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.