DelegatingFilterProxy ของ Spring MVC คืออะไร


120

ฉันเห็นสิ่งนี้ในแอป Spring MVC ของฉันweb.xml:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

ฉันพยายามหาสาเหตุว่าทำไมถึงอยู่ที่นั่นและจำเป็นจริงหรือไม่

ฉันพบคำอธิบายนี้ในเอกสาร Springแต่ไม่ได้ช่วยให้ฉันเข้าใจได้:

มันดูเหมือนว่าจะชี้ให้เห็นว่าส่วนนี้เป็น "กาว" ระหว่าง Servlets ที่กำหนดไว้ในและส่วนประกอบที่กำหนดไว้ในฤดูใบไม้ผลิweb.xmlapplicationContext.xml

7.1 DelegatingFilterProxy

เมื่อใช้ตัวกรอง servlet คุณต้องประกาศในตัวกรองของคุณอย่างชัดเจนweb.xmlมิฉะนั้นจะถูกละเว้นโดยคอนเทนเนอร์ servlet ใน Spring Security คลาสของตัวกรองยังเป็น Spring beans ที่กำหนดไว้ในบริบทของแอปพลิเคชันดังนั้นจึงสามารถใช้ประโยชน์จากสิ่งอำนวยความสะดวกในการฉีดแบบพึ่งพาและอินเทอร์เฟซวงจรชีวิตของ Spring Spring's DelegatingFilterProxyให้การเชื่อมโยงระหว่างweb.xmlและบริบทของแอปพลิเคชัน

เมื่อใช้ DelegatingFilterProxy คุณจะเห็นสิ่งนี้ในweb.xmlไฟล์:

<filter>
   <filter-name>myFilter</filter-name>
   <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
   <filter-name>myFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

สังเกตว่าจริงๆแล้วตัวกรองคือ a DelegatingFilterProxyไม่ใช่คลาสที่จะใช้ตรรกะของตัวกรองจริงๆ สิ่งที่DelegatingFilterProxyจะเป็นวิธีการมอบหมายของตัวกรองผ่านถั่วที่ได้จากบริบทของแอพลิเคชันฤดูใบไม้ผลิ สิ่งนี้ทำให้ bean ได้รับประโยชน์จากการสนับสนุนวงจรชีวิตบริบทของเว็บแอ็พพลิเคชัน Spring และความยืดหยุ่นในการกำหนดค่า bean ต้องใช้งานjavax.servlet.Filterและต้องมีชื่อเดียวกันกับในองค์ประกอบ filter-name อ่านJavadoc สำหรับ DelegatingFilterProxyสำหรับข้อมูลเพิ่มเติม

ถ้าฉันเอาสิ่งนี้ออกไปweb.xmlจะเกิดอะไรขึ้น? servlets ของฉันไม่สามารถสื่อสารกับ Spring container ได้หรือไม่ **

คำตอบ:


127

มีเวทมนตร์บางอย่างอยู่ที่นี่ แต่ท้ายที่สุดแล้วทุกอย่างเป็นโปรแกรมกำหนด

DelegatingFilterProxyเป็นตัวกรองขณะที่มันกำลังอธิบายข้างต้นซึ่งมีเป้าหมายคือ " การมอบหมายให้เป็นถั่วฤดูใบไม้ผลิที่มีการจัดการที่ใช้อินเตอร์เฟซที่กรอง " คือว่าก็พบว่าถั่ว ( "ถั่วเป้าหมาย" หรือ "ผู้ร่วมประชุม") ในการประยุกต์ใช้ในฤดูใบไม้ผลิของคุณ บริบทและเรียกใช้ มันเป็นไปได้ยังไงกัน? เนื่องจากถั่วนี้ใช้ javax.servlet.Filter จึงเรียกเมธอด doFilter

ถั่วเรียกว่าอะไร? DelegatingFilterProxy "รองรับ" targetBeanName "[... ] โดยระบุชื่อของถั่วเป้าหมายในบริบทแอ็พพลิเคชัน Spring"

ในขณะที่คุณเห็นใน web.xml ของคุณที่ชื่อถั่วคือ " springSecurityFilterChain "

ดังนั้นในบริบทของเว็บแอปพลิเคชันตัวกรองจะสร้างถั่วที่เรียกว่า "springSecurityFilterChain" ในบริบทแอปพลิเคชันของคุณจากนั้นมอบหมายให้ใช้งานผ่านวิธี doFilter ()

โปรดจำไว้ว่าบริบทแอปพลิเคชันของคุณถูกกำหนดด้วยไฟล์ APPLICATION-CONTEXT (XML) ทั้งหมด ตัวอย่างเช่น applicationContext.xml AND applicationContext-security.xml

เลยลองหาถั่วชื่อ "springSecurityFilterChain"ในช่วงหลัง ...

... และอาจเป็นไปไม่ได้ (เช่นถ้าคุณทำตามบทช่วยสอนหรือถ้าคุณกำหนดค่าความปลอดภัยโดยใช้ Roo)

นี่คือความมหัศจรรย์: มีองค์ประกอบใหม่สำหรับการกำหนดค่าความปลอดภัยเช่น

<http auto-config="true" use-expressions="true"> 

ตามที่อนุญาตโดยhttp://www.springframework.org/schema/security/spring-security-3.0.xsdจะดำเนินการ

เมื่อ Spring โหลดบริบทของแอปพลิเคชันโดยใช้ไฟล์ XML หากพบองค์ประกอบก็จะพยายามตั้งค่าการรักษาความปลอดภัย HTTP นั่นคือกองกรองและ URL ที่มีการป้องกันและลงทะเบียน FilterChainProxy ชื่อ "springSecurityFilterChain"

หรือคุณสามารถกำหนด bean ในรูปแบบคลาสสิกนั่นคือ:

<beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">

แต่แนะนำน้อยกว่าเนื่องจากคุณต้องกำหนดค่าจำนวนมาก (ตัวกรองทั้งหมดที่คุณจะใช้และมีมากกว่าหนึ่งโหล)


"applicationContext-security.xml AND applicationContext-security.xml" เป็นชื่อไฟล์เดียวกันสองครั้ง
musiKk

ขอบคุณ musiKk (ฉันคิดว่าคุณสามารถแก้ไขโพสต์ได้โดยตรง)
jbbarquero

นี่คือคำอธิบายที่ฉันมองหามาตลอดและเคลียร์สิ่งต่างๆให้ฉัน
user871611

@jbbarquero: คุณพูดถูก แต่ฉันไม่แน่ใจว่าเวอร์ชันที่ถูกต้องควรเป็นอย่างไร ฉันมักจะปล่อยให้ผู้เขียนต้นฉบับแก้ไขเพื่อที่จะไม่เปลี่ยนความหมายโดยไม่ได้ตั้งใจ
musiKk

ตกลง. ไม่ว่าในกรณีใดฉันขอขอบคุณมากที่คุณช่วยปรับปรุงคำตอบของฉัน ขอขอบคุณอีกครั้ง musiKk
jbbarquero

74

คุณรู้หรือไม่ว่าServlet Filterคืออะไรและทำงานอย่างไร? เป็นส่วนที่มีประโยชน์มากของ Servlet Spec ช่วยให้เราสามารถใช้แนวคิดคล้าย AOP ในการให้บริการคำขอ HTTP เฟรมเวิร์กจำนวนมากใช้การใช้งานตัวกรองสำหรับสิ่งต่างๆและไม่ใช่เรื่องแปลกที่จะพบการใช้งานแบบกำหนดเองเนื่องจากมันง่ายมากในการเขียนและมีประโยชน์ ในแอป Spring สิ่งต่างๆส่วนใหญ่ที่แอปของคุณทำได้อยู่ใน Spring beans แม้ว่าอินสแตนซ์ตัวกรองจะถูกควบคุมโดยคอนเทนเนอร์ Servlet คอนเทนเนอร์สร้างอินสแตนซ์เริ่มต้นและทำลายคอนเทนเนอร์ Servlet Spec ไม่จำเป็นต้องมีการผสานรวม Spring ใด ๆ ดังนั้นคุณจึงเหลือแนวคิด (ตัวกรอง) ที่มีประโยชน์มากโดยไม่มีวิธีที่สะดวกในการผูกเข้ากับแอป Spring และถั่วที่ใช้งานได้

ป้อน DelegatingFilterProxy คุณเขียนการนำตัวกรองไปใช้งานและทำให้เป็น Spring bean แต่แทนที่จะเพิ่มคลาสตัวกรองของคุณเองใน web.xml คุณใช้ DelegatingFilterProxy และตั้งชื่อ bean ของตัวกรองของคุณในบริบท Spring (หากคุณไม่ระบุชื่ออย่างชัดเจนจะใช้ "ชื่อตัวกรอง") จากนั้นในรันไทม์ DelegatingFilterProxy จะจัดการความซับซ้อนในการค้นหาการนำไปใช้งานจริงซึ่งเป็นชื่อที่คุณเขียนและกำหนดค่าใน Spring และกำหนดเส้นทางคำขอไปยัง . ดังนั้นในรันไทม์ก็เหมือนกับว่าคุณได้แสดงรายการตัวกรองของคุณใน web.xml แต่คุณจะได้รับประโยชน์จากความสามารถในการต่อสายเหมือนกับ Spring bean อื่น ๆ

หากคุณนำการแมปตัวกรองนั้นออกจาก web.xml ของคุณทุกอย่างจะยังคงทำงานต่อไป แต่จะไม่มีการรักษาความปลอดภัย URL ของคุณ (สมมติว่าชื่อ "springSecurityFilterChain" อธิบายสิ่งที่ทำอย่างถูกต้อง) นั่นเป็นเพราะการแมปนี้กรองคำขอที่เข้ามาทั้งหมดและส่งต่อไปยังตัวกรองความปลอดภัยที่กำหนดไว้ในบริบท Spring ของคุณ


ขอบคุณสำหรับการโพสต์ความคิดเห็นที่เปล่งประกายนี้ ตอนนี้ฉันกำลังเรียนรู้ Spring Security พยายามทำความเข้าใจให้มากพอที่จะทำการปรับแต่ง ฉันไม่รู้ว่าตัวกรอง servlet คืออะไรหรือตัวกรองสปริงคืออะไร บิตของคุณเกี่ยวกับ AOP ทำให้ชัดเจนว่าเหตุใดจึงมีตัวกรองแทนที่จะใช้เพียงแค่ servlets ........ ดังนั้นคุณไม่จำเป็นต้องเขียนการประมวลผลก่อน / หลังเดียวกันซ้ำแล้วซ้ำอีกในแต่ละ servlet / ทรัพยากร
Steve

ว้าว. คำอธิบายนั้นตรงกับที่ฉันต้องการ ขอบคุณที่แบ่งปันความรู้
Charles Morin

@Ryan Stewart ถ้าฉันมีสอง bean ใช้อินเทอร์เฟซตัวกรองใน applicationContext และฉันต้องการดำเนินการตามลำดับฉันจะทำมันได้อย่างไร
Abhishek Nayak

@skaffman ถ้าฉันมีสอง bean ใช้อินเทอร์เฟซตัวกรองใน applicationContext และฉันต้องการดำเนินการตามลำดับฉันจะทำมันได้อย่างไร
Abhishek Nayak

44

Servlet Filters คืออะไร?

โดยทั่วไปแล้วตัวกรอง Servletเป็นแนวคิดของ Java WebApp คุณสามารถมีตัวกรอง servlet ในเว็บแอปใดก็ได้ไม่ว่าคุณจะใช้ Spring framework ในแอปพลิเคชันของคุณหรือไม่ก็ตาม

ตัวกรองเหล่านี้สามารถสกัดกั้นคำขอก่อนที่จะไปถึง servlet เป้าหมาย คุณสามารถใช้ฟังก์ชันทั่วไปเช่นการอนุญาตในตัวกรอง servlet เมื่อติดตั้งแล้วคุณสามารถกำหนดค่าตัวกรองใน web.xml ของคุณเพื่อนำไปใช้กับ servlet เฉพาะรูปแบบ URL คำขอเฉพาะหรือรูปแบบ URL ทั้งหมด

ใช้ตัวกรอง servlet ที่ไหน

เว็บแอปสมัยใหม่สามารถมีตัวกรองดังกล่าวได้มากมาย สิ่งต่างๆเช่นการอนุญาตการแคชการจัดการเซสชัน ORM และการฉีดขึ้นต่อกันมักจะถูกนำมาใช้โดยใช้ตัวกรอง servlet web.xmlตัวกรองทั้งหมดเหล่านี้จะต้องลงทะเบียนใน

การสร้างอินสแตนซ์ตัวกรอง Servlet โดยไม่ต้องใช้ Spring Framework

คอนเทนเนอร์ servlet ของคุณสร้างอินสแตนซ์ของตัวกรองที่ประกาศในweb.xmlและเรียกใช้ในเวลาที่เหมาะสม (เช่นเมื่อให้บริการคำขอ servlet) ตอนนี้ถ้าคุณเป็นเหมือนแฟน ๆ Dependency Injection (DI) ส่วนใหญ่คุณคงจะพูดได้ว่าการสร้างอินสแตนซ์คือสิ่งที่ DI framework (Spring) ของฉันทำได้ดีกว่า ฉันไม่สามารถสร้างตัวกรอง servlet ด้วย Spring เพื่อให้สอดคล้องกับความดี DI ทั้งหมดได้หรือไม่?

DelegatingFilterProxyเพื่อให้ Spring สร้างอินสแตนซ์ตัวกรองของคุณ

นี่คือที่ที่DelegatingFilterProxyขั้นตอนในDelegatingFilterProxyคือการทำให้javax.servlet.Filterอินเทอร์เฟซที่จัดเตรียมโดย Spring Framework เมื่อคุณกำหนดค่าDelegatingFilterProxyใน web.xml คุณสามารถประกาศถั่วจริงที่ทำหน้าที่กรองในการกำหนดค่าสปริงของคุณ ด้วยวิธีนี้ Spring จะสร้างอินสแตนซ์ของถั่วที่ทำการกรองจริงและคุณสามารถใช้ DI เพื่อกำหนดค่าถั่วเหล่านี้ได้

โปรดทราบว่าคุณจำเป็นต้องมีDelegatingFilterProxyการประกาศเพียงครั้งเดียวweb.xmlแต่คุณสามารถมีการกรองหลายตัวbeanเชื่อมโยงกันในบริบทแอปพลิเคชันของคุณ


อธิบายได้ดีมาก
user4906240

15

สิ่งนี้คือตัวกรอง servlet ได้รับการจัดการโดย servlet container ไม่ใช่โดยสปริง และคุณอาจต้องฉีดส่วนประกอบสปริงเข้าไปในตัวกรองของคุณ

ดังนั้นหากคุณต้องการสิ่งที่ต้องการ:

public class FooFilter {

    @Inject
    private FooService service;

    public void doFilter(....) { .. }

}

จากนั้นคุณต้องมีพร็อกซีตัวกรองการมอบหมาย


1

คุณถนัดเรื่อง 'กาว' ตามที่เขียนไว้ใน JavaDocs ของFilterChainProxy :

FilterChainProxy เชื่อมโยงกับโซ่ตัวกรองคอนเทนเนอร์ของ servlet โดยการเพิ่มการประกาศ Spring DelegatingFilterProxy มาตรฐานในไฟล์ web.xml ของแอ็พพลิเคชัน

โปรดดูส่วน FIlterChainProxy ของบล็อกเบื้องหลัง Spring Security Namespaceสำหรับคำอธิบายที่ดีเยี่ยม


0

ฉันรู้สึกงงงวยโดย "springSecurityFilterChain" ใน web.xml และพบคำตอบนี้ในเอกสารความปลอดภัยของ springframework:

<http>องค์ประกอบความสุนทรีย์กำหนดค่าความปลอดภัยสำหรับชั้นเว็บของแอพลิเคชันของคุณ > จะสร้าง FilterChainProxy bean ชื่อ "springSecurityFilterChain" ซึ่งเก็บรักษาสแต็กของ> ตัวกรองความปลอดภัยซึ่งประกอบเป็นส่วนกำหนดค่าความปลอดภัยของเว็บ [19] ตัวกรองหลักบางตัวถูกสร้างขึ้นเสมอและตัวกรองอื่น ๆ จะถูกเพิ่มลงในสแต็กโดยขึ้นอยู่กับองค์ประกอบลูกของแอตทริบิวต์ซึ่งเป็น> ปัจจุบัน ตำแหน่งของตัวกรองมาตรฐานได้รับการแก้ไขแล้ว (ดูตารางลำดับตัวกรองใน> การแนะนำเนมสเปซ) โดยลบแหล่งที่มาของข้อผิดพลาดทั่วไปกับเฟรมเวิร์กเวอร์ชันก่อนหน้า> เมื่อผู้ใช้ต้องกำหนดค่าฟิลเตอร์เชนอย่างชัดเจนในFilterChainProxy bean แน่นอนคุณสามารถทำได้หากคุณต้องการควบคุมการกำหนดค่าทั้งหมด

นี่คือลิงค์http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-namespace.html


0

เป็นเวลานาน แต่ฉันมีคำถามเดียวกันและพบสิ่งนี้: https://www.javacodegeeks.com/2013/11/spring-security-behind-the-scenes.html

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

ดังนั้นยอมรับคำตอบของ @ Ryan

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