รหัสสถานะ HTTP ที่ถูกต้องคืออะไรเมื่อเปลี่ยนเส้นทางไปยังหน้าเข้าสู่ระบบ?


133

เมื่อผู้ใช้ไม่ได้เข้าสู่ระบบและพยายามเข้าถึงหน้าที่ต้องเข้าสู่ระบบรหัสสถานะ HTTP ที่ถูกต้องสำหรับการเปลี่ยนเส้นทางไปยังหน้าล็อกอินคืออะไร

ฉันขอเพราะไม่มี รหัสตอบกลับ 3xx ที่กำหนดโดย W3C ดูเหมือนว่าจะตรงกับข้อกำหนด:

10.3.1 300 ทางเลือกหลายทาง

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

เว้นแต่จะเป็นคำขอ HEAD การตอบสนองควรรวมเอนทิตีที่มีรายการลักษณะทรัพยากรและตำแหน่งที่ตั้งซึ่งผู้ใช้หรือตัวแทนผู้ใช้สามารถเลือกสิ่งที่เหมาะสมที่สุดได้ รูปแบบเอนทิตีถูกระบุโดยประเภทสื่อที่กำหนดในฟิลด์ส่วนหัวประเภทเนื้อหา ขึ้นอยู่กับรูปแบบและความสามารถของ

ตัวแทนผู้ใช้การเลือกตัวเลือกที่เหมาะสมที่สุดอาจดำเนินการโดยอัตโนมัติ อย่างไรก็ตามข้อกำหนดนี้ไม่ได้กำหนดมาตรฐานใด ๆ สำหรับการเลือกอัตโนมัติดังกล่าว

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

10.3.2 301 ย้ายถาวร

ทรัพยากรที่ร้องขอได้รับการกำหนด URI ถาวรใหม่และการอ้างอิงในอนาคตไปยังทรัพยากรนี้ควรใช้หนึ่งใน URI ที่ส่งคืน ไคลเอ็นต์ที่มีความสามารถในการแก้ไขลิงก์ควรเชื่อมโยงการอ้างอิงไปยัง Request-URI ใหม่โดยอัตโนมัติกับการอ้างอิงใหม่ที่เซิร์ฟเวอร์ส่งคืนหากเป็นไปได้ การตอบสนองนี้สามารถแคชได้เว้นแต่จะระบุไว้เป็นอย่างอื่น

URI ถาวรใหม่ควรได้รับจากฟิลด์ Location ในการตอบกลับ เว้นแต่วิธีการร้องขอคือ HEAD เอนทิตีของการตอบสนองควรมีไฮเปอร์เท็กซ์สั้น ๆ ที่มีไฮเปอร์ลิงก์ไปยัง URI ใหม่

หากได้รับรหัสสถานะ 301 ตามคำขออื่นที่ไม่ใช่ GET หรือ HEAD เอเจนต์ผู้ใช้จะต้องไม่เปลี่ยนเส้นทางคำขอโดยอัตโนมัติเว้นแต่จะได้รับการยืนยันจากผู้ใช้เนื่องจากอาจเปลี่ยนแปลงเงื่อนไขในการออกคำขอได้

  Note: When automatically redirecting a POST request after
  receiving a 301 status code, some existing HTTP/1.0 user agents
  will erroneously change it into a GET request.

10.3.3 302 พบ

ทรัพยากรที่ร้องขออยู่ชั่วคราวภายใต้ URI อื่น เนื่องจากการเปลี่ยนเส้นทางอาจมีการเปลี่ยนแปลงในบางครั้งไคลเอ็นต์จึงควรใช้ Request-URI ต่อไปสำหรับคำขอในอนาคต การตอบกลับนี้สามารถใช้แคชได้หากระบุโดยฟิลด์ส่วนหัว Cache-Control หรือ Expires

URI ชั่วคราวควรได้รับจากฟิลด์ Location ในการตอบกลับ เว้นแต่วิธีการร้องขอคือ HEAD เอนทิตีของการตอบสนองควรมีไฮเปอร์เท็กซ์สั้น ๆ ที่มีไฮเปอร์ลิงก์ไปยัง URI ใหม่

หากได้รับรหัสสถานะ 302 ตามคำขออื่นที่ไม่ใช่ GET หรือ HEAD เอเจนต์ผู้ใช้จะต้องไม่เปลี่ยนเส้นทางคำขอโดยอัตโนมัติเว้นแต่จะได้รับการยืนยันจากผู้ใช้เนื่องจากอาจเปลี่ยนแปลงเงื่อนไขในการออกคำขอ

  Note: RFC 1945 and RFC 2068 specify that the client is not allowed
  to change the method on the redirected request.  However, most
  existing user agent implementations treat 302 as if it

เป็นการตอบกลับ 303 โดยดำเนินการ GET ในค่าฟิลด์ตำแหน่งโดยไม่คำนึงถึงวิธีการร้องขอเดิม มีการเพิ่มรหัสสถานะ 303 และ 307 สำหรับเซิร์ฟเวอร์ที่ต้องการสร้างความชัดเจนอย่างชัดเจนว่าลูกค้าคาดหวังปฏิกิริยาใด

10.3.4 303 ดูอื่น ๆ

การตอบกลับคำขอสามารถพบได้ภายใต้ URI ที่แตกต่างกันและควรดึงข้อมูลโดยใช้เมธอด GET บนทรัพยากรนั้น วิธีนี้มีอยู่เป็นหลักเพื่ออนุญาตให้เอาต์พุตของสคริปต์ที่เปิดใช้งาน POST เปลี่ยนทิศทางตัวแทนผู้ใช้ไปยังรีซอร์สที่เลือก URI ใหม่ไม่ใช่การอ้างอิงทดแทนสำหรับทรัพยากรที่ร้องขอในตอนแรก การตอบกลับ 303 ต้องไม่ถูกแคช แต่การตอบกลับคำขอที่สอง (เปลี่ยนเส้นทาง) อาจเป็นแคชได้

URI ที่แตกต่างกันควรได้รับจากฟิลด์ Location ในการตอบกลับ เว้นแต่วิธีการร้องขอคือ HEAD เอนทิตีของการตอบสนองควรมีไฮเปอร์เท็กซ์สั้น ๆ ที่มีไฮเปอร์ลิงก์ไปยัง URI ใหม่

  Note: Many pre-HTTP/1.1 user agents do not understand the 303
  status. When interoperability with such clients is a concern, the
  302 status code may be used instead, since most user agents react
  to a 302 response as described here for 303.

10.3.5 304 ไม่ได้แก้ไข

หากไคลเอ็นต์ดำเนินการร้องขอ GET แบบมีเงื่อนไขและอนุญาตให้เข้าถึงได้ แต่เอกสารไม่ได้รับการแก้ไขเซิร์ฟเวอร์ควรตอบสนองด้วยรหัสสถานะนี้ การตอบกลับ 304 ต้องไม่มีเนื้อความดังนั้นจึงมักจะสิ้นสุดโดยบรรทัดแรกว่างหลังฟิลด์ส่วนหัว

คำตอบต้องมีฟิลด์ส่วนหัวต่อไปนี้:

  - Date, unless its omission is required by section 14.18.1 If a

เซิร์ฟเวอร์ต้นทางที่ไม่ใช้นาฬิกาปฏิบัติตามกฎเหล่านี้และพร็อกซีและไคลเอนต์จะเพิ่มวันที่ของตนเองลงในการตอบกลับใด ๆ ที่ได้รับโดยไม่มีวันที่ (ตามที่ระบุไว้แล้วโดย [RFC 2068] ส่วน 14.19) แคชจะทำงานได้อย่างถูกต้อง

  - ETag and/or Content-Location, if the header would have been sent
    in a 200 response to the same request
  - Expires, Cache-Control, and/or Vary, if the field-value might
    differ from that sent in any previous response for the same
    variant If the conditional GET used a strong cache validator (see

ส่วน 13.3.3) คำตอบไม่ควรรวมส่วนหัวของเอนทิตีอื่น ๆ มิฉะนั้น (กล่าวคือ GET ตามเงื่อนไขใช้ตัวตรวจสอบความถูกต้องที่อ่อนแอ) การตอบสนองจะต้องไม่รวมส่วนหัวของเอนทิตีอื่น ๆ สิ่งนี้จะป้องกันความไม่สอดคล้องกันระหว่างเนื้อหาเอนทิตีที่แคชและส่วนหัวที่อัปเดต

หากการตอบกลับ 304 ระบุว่าเอนทิตีไม่ได้ถูกแคชไว้แคชจะต้องไม่สนใจการตอบกลับและทำซ้ำคำขอโดยไม่มีเงื่อนไข

หากแคชใช้การตอบกลับ 304 ที่ได้รับเพื่ออัปเดตรายการแคชแคชจะต้องอัปเดตรายการเพื่อแสดงค่าฟิลด์ใหม่ที่ระบุในการตอบกลับ

10.3.6 305 ใช้ Proxy

ต้องเข้าถึงทรัพยากรที่ร้องขอผ่านพร็อกซีที่กำหนดโดยฟิลด์ตำแหน่ง ฟิลด์ตำแหน่งให้ URI ของพร็อกซี คาดว่าผู้รับจะทำซ้ำคำขอเดียวนี้ผ่านทางพร็อกซี 305 คำตอบต้องสร้างโดยเซิร์ฟเวอร์ต้นทางเท่านั้น

  Note: RFC 2068 was not clear that 305 was intended to redirect a
  single request, and to be generated by origin servers only.  Not
  observing these limitations has significant security consequences.

10.3.7 306 (ไม่ได้ใช้)

รหัสสถานะ 306 ถูกใช้ในข้อกำหนดรุ่นก่อนหน้านี้ไม่ได้ใช้อีกต่อไปและมีการสงวนรหัสไว้

10.3.8 307 การเปลี่ยนเส้นทางชั่วคราว

ทรัพยากรที่ร้องขออยู่ชั่วคราวภายใต้ URI อื่น เนื่องจากการเปลี่ยนเส้นทางอาจมีการเปลี่ยนแปลงในบางครั้งไคลเอนต์จึงควรใช้ Request-URI ต่อไปสำหรับคำขอในอนาคต การตอบกลับนี้สามารถใช้แคชได้หากระบุโดยฟิลด์ส่วนหัว Cache-Control หรือ Expires

URI ชั่วคราวควรได้รับจากฟิลด์ Location ในการตอบกลับ เว้นแต่วิธีการร้องขอคือ HEAD เอนทิตีของการตอบกลับควรมีไฮเปอร์เท็กซ์สั้น ๆ ที่มีไฮเปอร์ลิงก์ไปยัง URI ใหม่เนื่องจากเอเจนต์ผู้ใช้พรี HTTP / 1.1 จำนวนมากไม่เข้าใจสถานะ 307 ดังนั้นหมายเหตุควรมีข้อมูลที่จำเป็นสำหรับผู้ใช้ในการทำซ้ำคำขอเดิมใน URI ใหม่

หากได้รับรหัสสถานะ 307 ตามคำขออื่นที่ไม่ใช่ GET หรือ HEAD ตัวแทนผู้ใช้ต้องไม่เปลี่ยนเส้นทางคำขอโดยอัตโนมัติเว้นแต่จะได้รับการยืนยันจากผู้ใช้เนื่องจากอาจเปลี่ยนแปลงเงื่อนไขในการออกคำขอ

ตอนนี้ฉันใช้ 302 จนกระทั่งพบไฟล์ตอบที่ถูกต้อง

อัปเดตและสรุป:

HTTP 302 ดีกว่าเนื่องจากทราบว่ามีความเข้ากันได้ดีที่สุดกับไคลเอนต์ / เบราว์เซอร์


1
ฉันจะบอกว่าวิธีการจองอย่างแน่นอนคือการส่งคืน 401 และหน้าเข้าสู่ระบบโดยไม่มีการเปลี่ยนเส้นทาง แต่ฉันไม่แน่ใจว่าตัวเลือกของคุณคืออะไร
Nick Craver

1
@ จุดที่ดี แต่ฉันจะกลัวผลข้างเคียงถ้าฉันสร้างระบบล็อกอินแบบคลาสสิก
Pekka

1
@Pekka - เห็นด้วยอย่างยิ่งมันขึ้นอยู่กับว่าแพลตฟอร์มนี้เป็นอย่างไรเกี่ยวกับวิธีการจัดการทั้งหมดที่สามารถจัดการได้อย่างหมดจดและถ้าอินทราเน็ตกับอินเทอร์เน็ตเข้ามาเล่นฉันเชื่อว่า ... อย่างน้อยก็ในประสบการณ์ของฉัน
Nick Craver

@Nick With 401 "คำตอบต้องมีฟิลด์ส่วนหัว WWW-Authenticate" - ฉันจะรวมสิ่งนี้กับฐานข้อมูล MySQL ได้อย่างไร? AuthType Basic และ Digest ไม่ จำกัด เฉพาะไฟล์ config ของ apache เช่น. htpassword ฯลฯ ... ?
Vidar Vestnes

ฉันต้องการหน้าเข้าสู่ระบบที่กำหนดเองไม่ใช่กล่องโต้ตอบเบราว์เซอร์พื้นฐานที่ขอชื่อผู้ใช้และรหัสผ่าน ...
Vidar Vestnes

คำตอบ:


66

ฉันจะบอกว่า303 ดูอื่น ๆ 302 พบ:

ทรัพยากรที่ร้องขออยู่ชั่วคราวภายใต้ URI อื่น เนื่องจากการเปลี่ยนเส้นทางอาจมีการเปลี่ยนแปลงในบางครั้งไคลเอ็นต์จึงควรใช้ Request-URI ต่อไปสำหรับคำขอในอนาคต การตอบกลับนี้สามารถใช้แคชได้หากระบุโดยฟิลด์ส่วนหัว Cache-Control หรือ Expires

เหมาะกับหน้าเข้าสู่ระบบมากที่สุดในความคิดของฉัน ในตอนแรกฉันคิดว่า303 see otherสิ่งใดจะได้ผลเช่นกัน หลังจากที่บางคนคิดว่าผมพูด302 Foundมากขึ้นเหมาะสมเพราะทรัพยากรที่ร้องขอถูกพบมีเพียงหน้าไปผ่านก่อนที่จะสามารถเข้าถึงได้อีก การตอบกลับไม่ได้รับการแคชโดยค่าเริ่มต้นซึ่งก็ใช้ได้เช่นกัน


4
ฉันเห็นด้วย แต่ฉันคิดว่า 302 Found บ่งชี้ว่าพบทรัพยากรภายใต้ URL อื่น อดีต ฉันต้องการตอบข้อความของฉัน / เซิร์ฟเวอร์ด้วย 302 เพราะ "วันนี้" ข้อความของฉันอยู่ใน "/ เข้าสู่ระบบ /" (แทนที่จะเป็น "/ ข้อความ /") ... ฉันใช้ 302 แต่ฉันไม่รู้สึก บริบทตรงกัน 100% เนื่องจากหน้าเข้าสู่ระบบเป็นทรัพยากรที่แตกต่างกันและไม่มีเนื้อหาเหมือนกันตามที่ร้องขอ
Vidar Vestnes

2
@PHP_Jedi จริง. 303 อาจเหมาะสมกว่าจากมุมมองนั้น อย่างไรก็ตาม 302 มีความน่าเชื่อถือมากกว่าในแง่ของความเข้ากันได้ของไคลเอ็นต์
Pekka

1
ใช่ฉันคิดว่า 303 อาจเข้ากับบริบทได้ดีกว่าเนื่องจากระบุว่า "การตอบสนองต่อคำขอสามารถพบได้ภายใต้ URI อื่น" นี่เป็นการบอกฉันว่าไม่ใช่ทรัพยากรที่จะพบใน URI อื่น แต่เป็นการตอบสนองต่อคำขอนี้เท่านั้น
Vidar Vestnes

3
@PHP_Jedi ฉันไม่แน่ใจว่าจะคุ้มค่ากับการใช้เวลามากขนาดนี้ ทั้งไคลเอนต์และเซิร์ฟเวอร์ในโลก http จะต้องมีความเสรีมากและทนต่อความผิดพลาดได้ดังนั้นจะไม่มีความแตกต่างอย่างแท้จริงไม่ว่าคุณจะใช้302หรือ303ยกเว้นที่302รู้จักกันดีกว่า ฉันพบว่าระดับของรายละเอียดนั้นน่ายกย่องและเป็นเรื่องดีเสมอที่จะทำให้สิ่งต่างๆถูกต้อง แต่ความพยายามมากเกินไปอาจไร้ผลในพื้นที่เฉพาะนี้
Pekka

28
FYI: Google ออก 302s
David Murdoch

51

นี่เป็นการใช้กลไกการเปลี่ยนเส้นทาง HTTP ในทางที่ผิด หากผู้ใช้ไม่ได้รับอนุญาตแล้ว app 401 Unauthorizedของคุณจะต้องกลับมา ในกรณีที่ผู้ใช้ได้รับอนุญาต แต่ไม่มีสิทธิ์เข้าถึงทรัพยากรที่ร้องขอ403 Forbiddenจะต้องส่งคืน

คุณควรทำการเปลี่ยนเส้นทางในฝั่งไคลเอ็นต์เช่นโดยใช้จาวาสคริปต์ รหัสสถานะสำหรับการเปลี่ยนเส้นทางเนื่องจากการอนุมัติต้องไม่อยู่ การใช้ 30x สำหรับสิ่งนี้ไม่เป็นไปตาม HTTP

วิธีคิดเกี่ยวกับรหัสสถานะ HTTP โดย Mark Nottingham

401 Unauthorized เรียกกลไกการตรวจสอบคำขอของ HTTP

401 Unauthorizedรหัสสถานะต้องมีWWW-Authenticateส่วนหัวที่รองรับการตรวจสอบความถูกต้องประเภทต่างๆ:

WWW- รับรองความถูกต้อง: <type> realm = <realm>

Bearer, OAuth, Basic, Digest, Cookie ฯลฯ


20
401 อาจไม่เหมาะสมในบางกรณีเป็นA server generating a 401 (Unauthorized) response MUST send a WWW-Authenticate header field( RFC ) และไม่ใช่ทุกระบบการเข้าสู่ระบบที่ใช้ส่วนหัวนั้น
starbeamrainbowlabs

6
สมมติว่าคุณกำลังรีเฟรชหน้าที่มีการป้องกัน javascript ฝั่งไคลเอ็นต์จะไม่มีการเปลี่ยนแปลงใด ๆ ในการเรียกและเบราว์เซอร์จะแสดงหน้าต่างเข้าสู่ระบบแทนการเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าเข้าสู่ระบบดังนั้นวิธีเดียวคือใช้รหัส 30x
Claude Brisson

2
Golang ไม่สามารถใช้ 401 ในการเปลี่ยนเส้นทาง นั่นหมายความว่าเราควรใช้ 30 * สำหรับการเปลี่ยนเส้นทาง
EIMEI

4
@EIMEI ตามเหตุผลของคุณหากภาษาหรือไลบรารีอื่นบังคับให้คุณใช้ 401 อินเทอร์เน็ตก็จะถึงวาระ ประเด็นของฉัน: สิ่งที่คุณพูดชี้ให้เห็นถึงปัญหาของ Golang (แม้ว่าฉันจะพบว่ามันน่าแปลกใจที่มันจะมีการออกแบบที่ทำให้ไม่สามารถส่ง 401s ได้!)
Greg

2
@starbeamrainbowlabs มีแบบร่างสำหรับการตรวจสอบสิทธิ์ HTTP ที่ใช้คุกกี้เป็นตัวเลือกในส่วนหัว WWW-Authenticate ดูtools.ietf.org/html/draft-broyer-http-cookie-auth-00
aef

12

ฉันคิดว่าโซลูชันที่เหมาะสมคือส่วนหัว HTTP 401 (ไม่ได้รับอนุญาต)

http://en.wikipedia.org/wiki/HTTP_codes#4xx_Client_Error

จุดประสงค์ของส่วนหัวนี้คือเท่านี้ แต่แทนที่จะเปลี่ยนเส้นทางไปยังหน้าเข้าสู่ระบบกระบวนการที่ถูกต้องจะเป็นดังนี้:

  • ผู้ใช้ไม่ได้เข้าสู่ระบบพยายามเข้าถึงหน้าที่ จำกัด การเข้าสู่ระบบ
  • ระบบระบุว่าผู้ใช้ไม่ได้เข้าสู่ระบบ
  • ระบบส่งคืนส่วนหัว HTTP 401 และแสดงฟอร์มล็อกอินในการตอบกลับเดียวกัน (ไม่ใช่การเปลี่ยนเส้นทาง)

นี่เป็นแนวทางปฏิบัติที่ดีเช่นการจัดเตรียมหน้าเว็บ 404 ที่มีประโยชน์พร้อมลิงก์แผนผังเว็บไซต์และแบบฟอร์มการค้นหาเป็นต้น

แล้วพบกันใหม่.


20
RFC ระบุ: "การตอบกลับต้องมีฟิลด์ส่วนหัว WWW-Authenticate (ส่วน 14.46) ที่มีความท้าทายที่เกี่ยวข้องกับทรัพยากรที่ร้องขอ" การตอบกลับ 401 ใช้ได้เฉพาะเมื่อใช้แบบแผนการพิสูจน์ตัวตน HTTP เท่านั้น
bshacklett

4
ในกรณีนั้น 403 จะดีกว่าเนื่องจากระบุว่าการเข้าถึงเป็นสิ่งต้องห้ามเพียงอย่างเดียวและส่วนหัวการอนุญาตจะไม่ช่วย
olanod

@bshacklett WWW-Authenticate สามารถใช้ร่วมกับแผนการตรวจสอบสิทธิ์ได้หลายแบบ (เช่น Bearer, OAuth) ดูdeveloper.mozilla.org/en-US/docs/Web/HTTP/Headers/…และiana.org/assignments/http-authschemes/http-authschemes.xhtml
filip26

มีแบบร่างสำหรับการตรวจสอบสิทธิ์ HTTP ที่ใช้คุกกี้เป็นตัวเลือกในส่วนหัว WWW-Authenticate ดูtools.ietf.org/html/draft-broyer-http-cookie-auth-00
aef
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.