chain ที่วางผิดลำดับ แล้วแอปไม่ยอมสตาร์ต
สามบทที่ผ่านมามี SecurityFilterChainSecurityFilterChainรายการ filter ที่คำขอต้องเดินผ่านก่อนถึง `DispatcherServlet` · ประกาศเป็น bean · มีได้หลายตัว และตัวที่ matcher ตรงเป็นตัวแรกคือตัวที่ทำงาน ตัวเดียว กฎทุกข้อจึงอยู่ในที่เดียวกัน · ระบบจริงมักไม่เป็นแบบนั้น · API กับหน้าเว็บมักต้องการกฎคนละชุด
บทนี้ประกาศสองตัว แล้ววัดว่าเกิดอะไรขึ้น
สองตัว หนึ่งกว้าง หนึ่งแคบ
หัวข้อที่มีชื่อว่า “สองตัว หนึ่งกว้าง หนึ่งแคบ”ตัวที่ไม่ประกาศขอบเขต ครอบทุกคำขอโดยปริยาย
@Bean@Order(1)fun wide(http: HttpSecurity): SecurityFilterChain { http.authorizeHttpRequests { it.anyRequest().hasRole("ADMIN") } http.httpBasic { } return http.build()}@Bean@Order(2)fun narrow(http: HttpSecurity): SecurityFilterChain { http.securityMatcher("/open") http.authorizeHttpRequests { it.anyRequest().permitAll() } return http.build()}securityMatchersecurityMatcherการกำหนดว่า `SecurityFilterChain` ตัวหนึ่งครอบคำขอแบบไหน · chain ที่ไม่มี matcher ครอบทุกคำขอ · จึงกลืน chain ที่อยู่ถัดไปทั้งหมดถ้าประกาศไว้ก่อน คือสิ่งที่บอกว่า chain ตัวหนึ่งครอบคำขอแบบไหน · ตัวที่ไม่ประกาศ ครอบทุกอย่าง
@Order ของ chainchain orderลำดับที่ `FilterChainProxy` ไล่หา chain ที่ตรงกับคำขอ · มันหยุดที่ตัวแรกที่ตรง แล้วไม่ปรึกษาตัวที่เหลือ · กฎในตัวที่ถูกกลืนจึงไม่มีผล ทั้งที่ code อ่านดูเหมือนมี คือลำดับที่ระบบไล่หาตัวที่ตรง · เลขน้อยมาก่อน
ผมคาดว่ากฎจะเงียบหาย แต่แอปสร้าง bean ไม่สำเร็จเลย
หัวข้อที่มีชื่อว่า “ผมคาดว่ากฎจะเงียบหาย แต่แอปสร้าง bean ไม่สำเร็จเลย”ผมเดาผิด และการเดาผิดนี้เป็นเนื้อหาของบท
ตอนวางแผนคอร์ส ผมเขียนไว้ว่าคำขอไปที่ /open จะถูก chain กว้างรับไปก่อน
แล้วได้ 401 ส่วนกฎ permitAll ในตัวแคบจะไม่มีใครได้ใช้ · เงียบๆ แบบนั้น
การวัดตอบว่า แอปสร้าง bean ไม่สำเร็จเลย
org.springframework.security.web.UnreachableFilterChainExceptionไม่มีคำขอไหนถูกยิงเลย เพราะไม่มีเซิร์ฟเวอร์ให้ยิง
ในรุ่นก่อนหน้า การวางลำดับแบบนี้เป็นความผิดพลาดที่ทำงานได้ · แอปขึ้น คำขอวิ่ง และกฎที่คุณเขียนไว้อย่างตั้งใจก็ไม่เคยถูกใช้
ตอนนี้มันเป็นความผิดพลาดที่หยุดคุณตั้งแต่ต้น · นี่คือการเปลี่ยนแปลงที่ดี ต่อให้มันทำให้คุณเสียเวลาตอนอัปเกรด
สลับลำดับ แล้ววัดใหม่
หัวข้อที่มีชื่อว่า “สลับลำดับ แล้ววัดใหม่”เปลี่ยนแค่สองเลข ไม่แตะอย่างอื่น
ให้ตัวแคบเป็น @Order(1) และตัวกว้างเป็น @Order(2) · แอปสตาร์ตได้
| ทรง | GET /open | chain ที่รับ |
|---|---|---|
| กว้างก่อน | แอปสตาร์ตไม่ขึ้น | — |
| แคบก่อน | 200 | narrow |
รหัส 200 อย่างเดียวพิสูจน์ไม่ได้ว่า chain ไหนเป็นคนรับ เพราะทั้งสองตัว
อาจให้ 200 ได้ด้วยเหตุผลคนละอย่าง · ป้ายในช่องขวาจึงมาจาก filter ที่เราแทรก
เข้าไปในแต่ละ chain เพื่อเขียน header บอกชื่อตัวเอง
กฎที่เหลือจากบทนี้
หัวข้อที่มีชื่อว่า “กฎที่เหลือจากบทนี้”เรียงจากแคบไปกว้าง และให้ตัวที่ครอบทุกอย่างอยู่ท้ายสุดเสมอ
- chain ที่ไม่ประกาศ
securityMatcherต้องเป็นตัวสุดท้าย - chain ที่ประกาศไว้ ต้องเรียงจากขอบเขตแคบไปกว้าง
- อย่าเชื่อรหัสตอบกลับเพื่อพิสูจน์ว่า chain ไหนทำงาน ให้ใส่ป้ายแล้ววัดป้าย
สิ่งที่บทนี้ทิ้งไว้
หัวข้อที่มีชื่อว่า “สิ่งที่บทนี้ทิ้งไว้”จัดโครงเป็นแล้ว แต่ body ของคำตอบที่ปฏิเสธยังว่างเปล่าเหมือนบทที่ 1
ตั้งแต่บทแรกจนถึงบทนี้ ผู้เรียกที่ถูกปฏิเสธยังได้แต่ตัวเลข · บทถัดไปเอา body กลับเข้าสัญญาเดิม และวัดว่าต้องลงมือกี่ที่
- Spring Boot 4.1.1 · Spring Security 7.1.1 · Kotlin 2.4.10 · JDK 25
- รันซ้ำเองได้ด้วย
npm run verify:clinic-security· ต้องสั่งscripts/clinic-security/up.shก่อน เพราะทรงของบทที่ 7 ต้องใช้ฐานข้อมูล - ชื่อ exception กับป้ายของ chain ถูกตรึงไว้ที่
src/data/perf/clinic-security.tsและtest/course-clinic-security.test.tsผูกสิ่งที่บทนี้พิมพ์เข้ากับ file นั้น - Spring Security — Java Configuration
(เข้าถึง 2026-09-02) — การประกาศหลาย
SecurityFilterChainและsecurityMatcher
เช็กความเข้าใจ — บทที่ 4
ข้อ 1 / 3ประกาศ chain ที่ไม่มี `securityMatcher` ไว้เป็นตัวแรก แล้วเกิดอะไรขึ้น