Was bringt der DelegatingFilterProxy von Spring MVC?

120

Ich sehe dies in meinen Spring MVC-Apps web.xml:

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

Ich versuche herauszufinden, warum es da ist und ob es tatsächlich gebraucht wird.

Ich habe diese Erklärung in den Spring-Dokumenten gefunden, aber es hilft mir nicht, sie zu verstehen:

Es scheint darauf hinzudeuten, dass diese Komponente der "Klebstoff" zwischen den in definierten Servlets web.xmlund den in der Feder definierten Komponenten ist applicationContext.xml.

7.1 DelegatingFilterProxy

Wenn Sie Servlet-Filter verwenden, müssen Sie diese natürlich in Ihrem deklarieren web.xml, sonst werden sie vom Servlet-Container ignoriert. In Spring Security sind die Filterklassen auch Spring Beans, die im Anwendungskontext definiert sind und somit die umfangreichen Funktionen zur Abhängigkeitsinjektion und die Lebenszyklusschnittstellen von Spring nutzen können. Spring's DelegatingFilterProxystellt die Verbindung zwischen web.xmlund dem Anwendungskontext her.

Wenn Sie DelegatingFilterProxy verwenden, wird in der web.xmlDatei Folgendes angezeigt:

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

Beachten Sie, dass der Filter tatsächlich eine DelegatingFilterProxyist und nicht die Klasse, die die Logik des Filters tatsächlich implementiert. Sie DelegatingFilterProxydelegieren die Methoden des Filters an eine Bean, die aus dem Spring-Anwendungskontext abgerufen wird. Auf diese Weise kann die Bean von der Unterstützung des Lebenszyklus des Spring-Webanwendungskontexts und der Flexibilität bei der Konfiguration profitieren. Die Bean muss implementiert sein javax.servlet.Filterund denselben Namen wie das Element filter-name haben. Weitere Informationen finden Sie im Javadoc for DelegatingFilterProxy

Also, wenn ich das aus meinem herausnehme web.xml, was wird passieren? Meine Servlets können nicht mit dem Spring-Container kommunizieren? **

Thomas
quelle

Antworten:

127

Hier gibt es eine Art Magie, aber am Ende ist alles ein deterministisches Programm.

Der DelegatingFilterProxy ist ein Filter, wie oben erläutert, dessen Ziel es ist, " an eine von Spring verwaltete Bean zu delegieren, die die Filterschnittstelle implementiert ", dh eine Bean ("Ziel-Bean" oder "Delegat") in Ihrer Spring-Anwendung zu finden Kontext und ruft es auf. Wie ist es möglich? Da diese Bean javax.servlet.Filter implementiert, wird ihre doFilter-Methode aufgerufen.

Welche Bohne heißt? delegatingFilterProxy "Unterstützt einen" targetBeanName "[...] und gibt den Namen der Ziel-Bean im Spring-Anwendungskontext an."

Wie Sie in Ihrer web.xml gesehen haben die Bean " springSecurityFilterChain " .

Im Kontext einer Webanwendung instanziiert ein Filter eine Bean mit dem Namen "springSecurityFilterChain" in Ihrem Anwendungskontext und delegiert sie dann über die Methode doFilter () an sie.

Denken Sie daran, dass Ihr Anwendungskontext mit ALLEN XML-Dateien (APPLICATION-CONTEXT) definiert ist. Zum Beispiel: applicationContext.xml UND applicationContext-security.xml.

Also versuche es in letzterem eine Bean namens "springSecurityFilterChain" finden ...

...und wahrscheinlich auch nicht (zum Beispiel, wenn Sie einem Tutorial gefolgt sind oder wenn Sie die Sicherheit mit Roo konfiguriert haben)

Hier ist die Magie: Es gibt ein neues Element zum Konfigurieren der Sicherheit , so etwas wie

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

wie es erlaubt ist http://www.springframework.org/schema/security/spring-security-3.0.xsd , wird es den Trick tun.

Wenn Spring den Anwendungskontext mithilfe von XML-Dateien lädt und ein Element findet, versucht es, die HTTP-Sicherheit, dh einen Filterstapel und geschützte URLs, einzurichten und den FilterChainProxy mit dem Namen "springSecurityFilterChain" zu registrieren.

Alternativ können Sie die Bohne auf klassische Weise definieren, dh:

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

Es wird jedoch weniger empfohlen, da Sie viel konfigurieren müssen (alle Filter, die Sie verwenden werden. Und es gibt mehr als ein Dutzend davon).

jbbarquero
quelle
"applicationContext-security.xml UND applicationContext-security.xml" ist zweimal der gleiche Dateiname.
musiKk
Danke musiKk (ich denke, Sie können den Beitrag direkt bearbeiten)
jbbarquero
Dies war die Erklärung, dass ich die ganze Zeit nachgesehen und die Dinge für mich geklärt habe.
user871611
@jbbarquero: Du hast recht, aber ich war mir nicht sicher, wie die richtige Version aussehen sollte. Ich neige dazu, dies dem ursprünglichen Autor zu überlassen, um die Bedeutung nicht versehentlich zu ändern.
musiKk
OK. Auf jeden Fall schätze ich Ihre Hilfe zur Verbesserung meiner Reaktion sehr. Nochmals
vielen
73

Wissen Sie, was ein Servlet-Filter ist und wie er funktioniert? Es ist ein sehr nützlicher Teil der Servlet-Spezifikation, mit dem wir AOP-ähnliche Konzepte auf die Bearbeitung von HTTP-Anforderungen anwenden können. Viele Frameworks verwenden Filterimplementierungen für verschiedene Zwecke, und es ist nicht ungewöhnlich, benutzerdefinierte Implementierungen davon zu finden, da sie sehr einfach zu schreiben und nützlich sind. In einer Spring-App ist das meiste, was Ihre App tun kann, in Ihren Spring Beans. Eine Filterinstanz wird jedoch vom Servlet-Container gesteuert. Der Container instanziiert, initialisiert und zerstört ihn. Die Servlet-Spezifikation erfordert jedoch keine Spring-Integration, sodass Sie ein wirklich nützliches Konzept (Filter) haben, das Sie nicht bequem an Ihre Spring-App und die Beans binden können, die die Arbeit erledigen.

Geben Sie den DelegatingFilterProxy ein. Sie schreiben eine Filter-Implementierung und machen sie zu einer Spring-Bean. Anstatt der web.xml eine eigene Filter-Klasse hinzuzufügen, verwenden Sie DelegatingFilterProxy und geben ihr im Spring-Kontext den Bean-Namen Ihres Filters. (Wenn Sie keinen expliziten Namen angeben, wird der "Filtername" verwendet.) Zur Laufzeit übernimmt DelegatingFilterProxy dann die Komplexität, die tatsächliche Implementierung - die in Spring geschriebene und konfigurierte - zu finden und Anforderungen an diese weiterzuleiten . Zur Laufzeit ist es so, als hätten Sie Ihren Filter in der Datei web.xml aufgelistet, aber Sie haben den Vorteil, dass Sie ihn wie jede andere Spring Bean verkabeln können.

Wenn Sie diese Filterzuordnung aus Ihrer web.xml entfernen, funktioniert alles weiter, aber keine Ihrer URLs wird gesichert. (Vorausgesetzt, der Name "springSecurityFilterChain" beschreibt genau, was er tut.) Dies liegt daran, dass diese Zuordnung jede eingehende Anforderung filtert und an einen Sicherheitsfilter weitergibt, der in Ihrem Spring-Kontext definiert ist.

Ryan Stewart
quelle
Vielen Dank für die Veröffentlichung dieses aufschlussreichen Kommentars. Ich lerne jetzt Spring Security und versuche, es genug zu verstehen, um Anpassungen vornehmen zu können. Ich hatte keine Ahnung, was Servlet-Filter sind oder was Federfilter sind. Ihr Beitrag zu AOP macht deutlich, WARUM man Filter haben würde, anstatt nur Servlets zu verwenden. Sie müssen also nicht immer wieder dieselbe Vor- / Nachbearbeitung in jedes Servlet / jede Ressource schreiben
Steve
Beeindruckend. Diese Erklärung ist genau das, was ich brauchte. Vielen Dank für das Teilen Ihres Wissens.
Charles Morin
@ Ryan Stewart Wenn ich zwei Beans habe, implementiert die Filterschnittstelle in applicationContext und ich möchte sie in einer Reihenfolge ausführen. Wie kann ich sie dann erstellen?
Abhishek Nayak
@skaffman Wenn ich zwei Beans habe, implementiert die Filterschnittstelle in applicationContext und ich möchte sie in einer Reihenfolge ausführen. Wie kann ich sie dann erstellen?
Abhishek Nayak
44

Was sind Servlet-Filter?

Servlet-Filter sind im Allgemeinen ein Java WebApp-Konzept. Sie können Servlet-Filter in jeder Webanwendung verwenden, unabhängig davon, ob Sie Spring Framework in Ihrer Anwendung verwenden oder nicht.

Diese Filter können Anforderungen abfangen, bevor sie das Zielservlet erreichen. Sie können allgemeine Funktionen wie die Autorisierung in Servlet-Filtern implementieren. Nach der Implementierung können Sie den Filter in Ihrer web.xml so konfigurieren, dass er auf ein bestimmtes Servlet, bestimmte Anforderungs-URL-Muster oder alle URL-Muster angewendet wird.

Wo werden Servlet-Filter eingesetzt?

Moderne Web-Apps können Dutzende solcher Filter haben. Dinge wie Autorisierung, Caching, ORM-Sitzungsverwaltung und Abhängigkeitsinjektion werden häufig mit Hilfe eines Servlet-Filters implementiert. Alle diese Filter müssen registriert sein web.xml.

Instantiieren von Servlet-Filtern - ohne Spring Framework

Ihr Servlet-Container erstellt Instanzen von Filtern, die in deklariert sind, web.xmlund ruft sie zu geeigneten Zeiten auf (dh wenn Servlet-Anforderungen bearbeitet werden). Wenn Sie wie die meisten DI-Fans (Dependency Injection) sind, würden Sie wahrscheinlich sagen, dass das Erstellen von Instanzen das ist, was mein DI-Framework (Spring) besser kann. Kann ich meine Servlet-Filter nicht mit Spring erstellen lassen, damit sie für alle DI-Vorteile geeignet sind?

DelegatingFilterProxy, damit Spring Ihre Filterinstanzen erstellt

Hier DelegatingFilterProxytritt ein. Dies ist DelegatingFilterProxyeine Verbesserung der javax.servlet.Filtervon Spring Framework bereitgestellten Schnittstelle. Sobald Sie DelegatingFilterProxyin web.xml konfiguriert haben , können Sie die tatsächlichen Beans deklarieren , die die Filterung in Ihrer Spring-Konfiguration durchführen. Auf diese Weise erstellt Spring die Instanzen von Beans, die die eigentliche Filterung durchführen, und Sie können DI verwenden, um diese Beans zu konfigurieren.

Beachten Sie, dass Sie nur eine einzige DelegatingFilterProxyDeklaration in benötigen, web.xmlaber mehrere Filter beanin Ihrem Anwendungskontext miteinander verkettet haben können .

Tahir Akhtar
quelle
sehr gut erklärt.
user4906240
15

Die Sache ist, Servlet-Filter werden vom Servlet-Container und nicht von der Feder verwaltet. Möglicherweise müssen Sie einige Federkomponenten in Ihre Filter einspritzen.

Also, wenn Sie etwas brauchen wie:

public class FooFilter {

    @Inject
    private FooService service;

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

}

Dann benötigen Sie den delegierenden Filter-Proxy.

Bozho
quelle
1

Sie haben Recht mit "Kleber" Zeug. Wie in JavaDocs von FilterChainProxy geschrieben :

FilterChainProxy wird durch Hinzufügen einer Standard-Spring DelegatingFilterProxy-Deklaration in der Anwendungsdatei web.xml mit der Filterkette des Servlet-Containers verknüpft.

Eine ausgezeichnete Erklärung finden Sie im Abschnitt FIlterChainProxy des Blogs Behind the Spring Security Namespace .

Ritesh
quelle
0

"SpringSecurityFilterChain" in web.xml hat mich verwirrt und diese Antwort im springframework-Sicherheitsdokument gefunden:

Das <http>Element kapselt die Sicherheitskonfiguration für die Webschicht Ihrer Anwendung. > Es wird eine FilterChainProxy-Bean mit dem Namen "springSecurityFilterChain" erstellt, die den Stapel von> Sicherheitsfiltern verwaltet, aus denen die Web-Sicherheitskonfiguration besteht [19]. Einige Kernfilter werden immer erstellt, andere werden dem Stapel hinzugefügt, abhängig von den Attributen der untergeordneten Elemente, die vorhanden sind. Die Positionen der Standardfilter sind festgelegt (siehe Tabelle zur Filterreihenfolge in der> Namespace-Einführung), wodurch eine häufige Fehlerquelle bei früheren Versionen des Frameworks beseitigt wird,> wenn Benutzer die Filterkette explizit in der FilterChainProxy-Bean konfigurieren mussten. Sie können dies natürlich trotzdem tun, wenn Sie die vollständige Kontrolle über die Konfiguration benötigen.

Hier ist der Link http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-namespace.html

Janet
quelle
0

Es ist lange her, aber ich hatte die gleiche Frage und fand diese: https://www.javacodegeeks.com/2013/11/spring-security-behind-the-scenes.html

Ich habe versucht, mein Frühjahrssicherheitsprojekt auszuführen, indem ich den betreffenden Filter entfernt und auch hinzugefügt habe. Was ich gefunden habe, ist, wenn wir den Filter hinzufügen, nur dann wird der Anruf zur erforderlichen Anmeldeseite umgeleitet, wie in der Spring-Security-Konfiguration definiert.

Daher stimme ich der Antwort von @ Ryan zu.

Außer Sinnen
quelle