Zertifizierungs- / Autorisierungsgeschichte Remember-Me-Geschichte CSRF-Geschichte Session Management Story Die Geschichte des Antwortheaders Method Security Story CORS-Geschichte Die Geschichte von Run-As Die Geschichte von ACL Teststory Sprechen Sie über die Zusammenarbeit mit MVC und Boot
Sonderedition Was Spring Security kann und was nicht
Java 1.8.0_xxx
Tomcat 8.0.35
Gradle 3.2.1
OS Windows 10
Eines der Projekte von Spring. Ein Framework, das Webanwendungen hauptsächlich Sicherheitsfunktionen hinzufügt.
Es bietet Schutz vor verschiedenen bekannten Angriffen wie CSRF- und Sitzungsfixierungsangriffen.
Hello World Hier ist in etwas mehr Reihenfolge für die Ankündigung geschrieben. Es ist möglicherweise einfacher zu verstehen, wenn Sie es zusammen mit der Folie lesen (ich denke, dass es nur auf der Folie geschrieben wurde).
Ordnerstruktur
|-build.gradle
`-src/main/webapp/
|-index.jsp
`-WEB-INF/
|-applicationContext.xml
`-web.xml
build.gradle
apply plugin: 'war'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
compileJava.options.encoding = 'UTF-8'
repositories {
mavenCentral()
}
dependencies {
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
compile 'javax.servlet:jstl:1.2'
compile 'org.springframework.security:spring-security-web:4.2.1.RELEASE'
compile 'org.springframework.security:spring-security-config:4.2.1.RELEASE'
}
war.baseName = 'spring-security-sample'
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login />
<sec:logout />
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="hoge" password="HOGE" authorities="ROLE_USER" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
index.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello Spring Security!!</title>
</head>
<body>
<h1>Hello Spring Security!!</h1>
<c:url var="logoutUrl" value="/logout" />
<form action="${logoutUrl}" method="post">
<input type="submit" value="logout" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
</html>
Generieren Sie eine Kriegsdatei (spring-security-sample.war
) mit gradle war
und stellen Sie sie für Tomcat bereit.
Öffnen Sie nach Abschluss der Bereitstellung "http: // localhost: 8080 / spring-security-sample" in Ihrem Browser.
Ein mysteriöser Anmeldebildschirm wird angezeigt.
Geben Sie "hoge" und "HOGE" in Benutzer und Passwort ein und klicken Sie auf die Schaltfläche "Anmelden".
Der Inhalt von index.jsp
wird angezeigt.
Klicken Sie abschließend auf die Schaltfläche "Abmelden".
Die Abmeldung ist abgeschlossen und Sie kehren zum Anmeldebildschirm zurück.
build.gradle
compile 'org.springframework.security:spring-security-web:4.2.1.RELEASE'
compile 'org.springframework.security:spring-security-config:4.2.1.RELEASE'
In der Mindestkonfiguration können Sie "spring-security-web" und "spring-security-config" als Abhängigkeiten hinzufügen (es scheint gut zu sein) (http://docs.spring.io/spring-security/site/docs/4.2.1). .RELEASE / reference / htmlsingle / #gradle).
spring-security-web
Es enthält Code für "Filter" und Web-Apps. Wenn Sie eine Webauthentifizierung oder eine URL-basierte Zugriffskontrolle benötigen, benötigen Sie dieses Modul. Das Hauptpaket ist "org.springframework.security.web"
spring-security-config
Es enthält Code zum Parsen des Namespace zum Schreiben von Definitionen in XML und Code für die Java-Konfiguration. Dieses Modul wird für XML-basierte Konfiguration und Java-Konfigurationen benötigt. Das Hauptpaket ist "org.springframework.security.config" Die hier enthaltenen Klassen werden von der Anwendung nicht direkt verwendet.
web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Durch die Registrierung von "ContextLoaderListener" als Listener wird der Spring-Container ("ApplicationContext") initialisiert.
Wenn Sie nicht angeben, was für die Klasse "ApplicationContext" verwendet werden soll, wird standardmäßig "XmlWebApplicationContext" verwendet.
Es wird in org / springframework / web / context / ContextLoader.properties
von spring-web-x.x.x.RELEASE.jar
wie folgt definiert und von ContextLoaderListener
geladen, wenn der Servlet-Container initialisiert wird.
ContextLoader.properties
# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
XmlWebApplicationContext
lädt standardmäßig WEB-INF / applicationContext.xml
als Konfigurationsdatei.
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login />
<sec:logout />
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="hoge" password="HOGE" authorities="ROLE_USER" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
applicationContext.xml
selbst ist eine Standardkonfigurationsdatei für die Spring Bean-Definition, keine spezielle Konfigurationsdatei für Spring Security.
Durch Laden von "http: // www.springframework.org / schema / security" mit "xmlns" können Sie das Tag für Spring Security verwenden (verwenden Sie in der Referenz dieses Tag für Spring Security * Wir nennen es * Namespace **). Mit diesem Tag können Sie die Spring Security-Einstellungen für diese Datei konfigurieren.
Die obigen Einstellungen definieren ungefähr Folgendes:
/ login
zugreifen ( allowAll
)/ **
) muss authentifiziert sein (isAuthenticated ()
)Die einzelnen Tags werden im Folgenden etwas detaillierter beschrieben.
<http>
Wenn Sie das
FilterChainProxy
SecurityFilterChain
FilterChainProxy
ist im Container mit dem Bean-Namen "springSecurityFilterChain"
registriert. </ span>
Diese Klasse ist das Gateway zur Spring Security-Verarbeitung.
SecurityFilterChain
ist nur eine Schnittstelle für sich, und DefaultSecurityFilterChain
ist im Container als Implementierungsklasse registriert.
Wie der Name schon sagt, ist "SecurityFilterChain" eine Kette von "javax.servlet.Filter", die eine Sicherheitsfunktion hat und mehrere "Filter" enthält.
Spring Security realisiert die Sicherheitsfunktion mithilfe von "Filter".
Wie Sie unter dem Namen "FilterChainProxy" sehen können, tut die Klasse selbst nichts. Die spezifische Verarbeitung wird an die Filter der SecurityFilterChain delegiert.
<intercept-url>
Die für den Zugriff erforderlichen Bedingungen (Zugriffskontrolle) werden für jedes URL-Muster definiert.
Das Attribut pattern
kann im Ameisenpfadformat beschrieben werden.
Geben Sie im Attribut "Zugriff" die Bedingungen an, die für den Zugriff auf die im Attribut "Muster" angegebene URL erforderlich sind.
allowAll
bedeutet, den gesamten Zugriff zuzulassen (keine Authentifizierung erforderlich).
Und "isAuthenticated ()" bedeutet, den Zugriff zuzulassen, wenn er authentifiziert (angemeldet) ist.
Das Attribut "access" wird in der Spring-eigenen Ausdruckssprache Spring Expression Language (SpEL) beschrieben.
<form-login>
Definiert, dass eine Formularauthentifizierung erforderlich ist.
Im Falle eines Authentifizierungsfehlers werden Sie standardmäßig zu "/ login" umgeleitet. Wenn Sie auf "/ login" zugreifen, gelangen Sie standardmäßig zu einer einfachen Anmeldeseite, die von Spring Security bereitgestellt wird.
Diese Standard-Anmeldeseite wird von "DefaultLoginPageGeneratingFilter" in "spring-security-web-x.x.x.RELEASE.jar" generiert.
<logout>
Durch Hinzufügen dieses Tags können Sie sich abmelden.
Standardmäßig werden Sie durch eine POST-Anforderung an "/ logout" abgemeldet.
<authentication-manager>
Definieren Sie "AuthenticationManager" als Bean.
AuthenticationManager
ist eine Klasse, die die Authentifizierungsverarbeitung ausführt und definiert werden muss.
AuthenticationManager
selbst ist eine Schnittstelle, und ProviderManager
wird für die Implementierungsklasse verwendet.
ProviderManager
selbst führt keine spezifische Authentifizierungsverarbeitung durch, delegiert jedoch die Authentifizierungsverarbeitung an AuthenticationProvider
, der später beschrieben wird.
<authentication-provider>
Definieren Sie "AutheticationProvider" als Bean. Diese Schnittstelle bietet eine spezifische Authentifizierungsverarbeitung entsprechend der Art der Authentifizierung.
Die Klasse, die die LDAP-Authentifizierungsverarbeitung bereitstellt, ist beispielsweise "LdapAuthenticationProvider".
Wenn Sie dieses Tag deklarieren, wird "DaoAuthenticationProvider" im Container registriert. Diese Klasse ruft Benutzerinformationen von "UserDetailsService" ab und führt die Authentifizierungsverarbeitung durch.
<user-service>
Registrieren Sie "UserDetailsService" als Bean. Diese Schnittstelle bietet die Möglichkeit, detaillierte Benutzerinformationen ("UserDetails") abzurufen.
Wenn Sie dieses Tag deklarieren, wird "InMemoryUserDetailsManager" im Container registriert. Wie der Name schon sagt, enthält diese Klasse Benutzerinformationen im Speicher. Es ist sozusagen eine temporäre Implementierung für die Betriebsprüfung.
<user>
Definieren Sie eine Instanz von "UserDetails". Diese Schnittstelle definiert die Getter-Methode usw. für den Zugriff auf detaillierte Benutzerinformationen.
Durch Deklarieren dieses Tags wird eine Instanz der Klasse "User" erstellt.
Mit den Attributen "Name", "Kennwort" und "Berechtigungen" können Sie Namen, Kennwörter und Berechtigungen zur Identifizierung von Benutzern angeben.
web.xml
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Definieren Sie "DelegatingFilterProxy" als Servlet-Filter in "web.xml".
Zu diesem Zeitpunkt wird "
DelegatingFilterProxy
ruft eine Bean ab, die javax.servlet.Filter
aus dem Spring-Container implementiert, wobei der Name in ihrem eigenen<Filtername>
festgelegt wird.
Und es ist ein Servlet-Filter, der nur die Verarbeitung an diese Bean delegiert.
Hier wird "springSecurityFilterChain" für "FilterChainProxy
-Bean-Namen , der automatisch im Container registriert wird, wenn Sie das<http>
-Tag in applicationContext.xml
verwenden. Ich mache es.
Mit anderen Worten, "DelegatingFilterProxy" ist für die Überbrückung des Servlet-Filters und der Spring Security ("FilterChainProxy") verantwortlich.
index.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello Spring Security!!</title>
</head>
<body>
<h1>Hello Spring Security!!</h1>
<c:url var="logoutUrl" value="/logout" />
<form action="${logoutUrl}" method="post">
<input type="submit" value="logout" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
</html>
Standardmäßig sind CSRF-Maßnahmen aktiviert. Daher ist es beim Senden einer Anfrage erforderlich, ein Token für CSRF-Gegenmaßnahmen gemeinsam zu übergeben.
Token-Werte und Parameternamen werden im Anforderungsbereich als "_csrf" gespeichert.
Eine detailliertere Erläuterung der CSRF-Maßnahmen wird zu einem späteren Zeitpunkt erfolgen. .. ..
Fassen Sie zusammen, wie der Prozess hinter den Kulissen zwischen dem Starten des Servers und dem Anmelden abläuft.
Ich verwende ein Sequenzdiagramm, aber es ist nicht schlecht, da es der Klarheit halber nicht der strengen UML-Notation folgt.
Obwohl es teilweise nicht streng ist, denke ich, dass der Initialisierungs- → Authentifizierungsprozess in der folgenden Atmosphäre durchgeführt wird.
DelegateFilterProxy
, das in web.xml
als Filter
registriert ist, wird vom Servlet-Container generiert.Es ist auch nicht streng, aber ich denke, der Ablauf, wenn Sie zum Anmeldebildschirm umgeleitet werden, wenn Sie ohne Anmeldung darauf zugreifen, ist wie folgt.
FilterSecurityInterceptor
ruft den Authentifizierungsprozess von AuthenticationManager
auf.AuthenticationManager
führt den Authentifizierungsprozess durch, löst jedoch AuthenticationException
aus, da es nicht authentifiziert ist.ExceptionTranslationFilter
fängt die ausgelöste Ausnahme ab.LoginUrlAuthenticationEntryPoint
leitet Sie zum Anmeldebildschirm weiter.Der Ablauf von unmittelbar nach der Umleitung zu "/ login" durch "LoginUrlAuthenticationEntryPoint" zur Anmeldung durch Eingabe des Benutzernamens und des Kennworts.
DefaultLoginPageGeneratingFilter
generiert den Standard-Anmeldebildschirm./ login
eine POST-Anfrage vorliegt, delegiert UsernamePasswordAuthenticationFilter
den Authentifizierungsprozess an AuthenticationManager
.UsernamePasswordAuthenticationFilter
die Verarbeitung, wenn die Authentifizierung erfolgreich ist, an AuthenticationSuccessFilter
.SavedRequestAwareAuthenticationSuccessHandler
, eine Implementierungsklasse von AuthenticationSuccessFilter
, stellt die URL wieder her und leitet sie weiter, bevor Sie zum Anmeldebildschirm weitergeleitet wurden.HttpSession
gespeichert.applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login />
<sec:logout />
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="hoge" password="HOGE" authorities="ROLE_USER" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
Der Namespace (dediziertes Tag) registriert automatisch die verschiedenen Beans, die zum Ausführen von Spring Security im Container erforderlich sind. Dank dessen sind die Spring Security-Einstellungen sehr einfach zu schreiben.
Wenn es jedoch erforderlich wird, die Authentifizierungsfunktion zu erweitern, ist es wichtig zu verstehen, welche Bohnen hinter den Kulissen registriert sind und welche Beziehung sie haben.
Um dies zu verstehen, schreiben wir die in Hello World erstellte Konfigurationsdatei ohne Verwendung des Namespace neu.
Ich werde jedoch nicht mein Bestes tun, um die Einstellung im Namespace genau anzupassen, sondern um die in Hello World angezeigten Anmeldevorgänge zu reproduzieren. Daher werden einige Bean-Definitionen weggelassen.
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<bean id="springSecurityFilterChain"
class="org.springframework.security.web.FilterChainProxy">
<constructor-arg ref="securityFilterChain" />
</bean>
<bean id="securityFilterChain"
class="org.springframework.security.web.DefaultSecurityFilterChain">
<constructor-arg index="0">
<bean class="org.springframework.security.web.util.matcher.AnyRequestMatcher" />
</constructor-arg>
<constructor-arg index="1">
<list>
<ref bean="securityContextPersistenceFilter" />
<ref bean="csrfFilter" />
<ref bean="logoutFilter" />
<ref bean="usernamePasswordAuthenticationFilter" />
<ref bean="defaultLoginPageGeneratingFilter" />
<ref bean="exceptionTranslationFilter" />
<ref bean="filterSecurityInterceptor" />
</list>
</constructor-arg>
</bean>
<!--SecurityContextHolder initialisieren / löschen-->
<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />
<!-- CSRF -->
<bean id="csrfFilter"
class="org.springframework.security.web.csrf.CsrfFilter">
<constructor-arg ref="csrfTokenRepository" />
</bean>
<bean id="csrfTokenRepository"
class="org.springframework.security.web.csrf.LazyCsrfTokenRepository">
<constructor-arg>
<bean class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository" />
</constructor-arg>
</bean>
<!--Ausloggen-->
<bean id="logoutFilter"
class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg index="0" value="/login?logout" />
<constructor-arg index="1">
<list>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
<bean class="org.springframework.security.web.csrf.CsrfLogoutHandler">
<constructor-arg ref="csrfTokenRepository" />
</bean>
</list>
</constructor-arg>
</bean>
<!--Login-Authentifizierung-->
<bean id="usernamePasswordAuthenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login?error" />
</bean>
</property>
</bean>
<!--Generieren Sie eine Standard-Anmeldeseite-->
<bean id="defaultLoginPageGeneratingFilter"
class="org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter">
<constructor-arg ref="usernamePasswordAuthenticationFilter" />
<property name="authenticationUrl" value="/login" />
</bean>
<!--Authentifizierungsausnahmehandler-->
<bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<constructor-arg>
<bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<constructor-arg value="/login" />
</bean>
</constructor-arg>
</bean>
<!--Authentifizierungs- / Autorisierungsverarbeitung-->
<bean id="filterSecurityInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource" ref="securityMetadataSource" />
</bean>
<!--Authentifizierungsverarbeitungskörper-->
<bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<constructor-arg>
<list>
<bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<bean class="org.springframework.security.provisioning.InMemoryUserDetailsManager">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.userdetails.User">
<constructor-arg index="0" value="hoge" />
<constructor-arg index="1" value="HOGE" />
<constructor-arg index="2">
<bean class="org.springframework.security.core.authority.AuthorityUtils"
factory-method="commaSeparatedStringToAuthorityList">
<constructor-arg value="ROLE_USER" />
</bean>
</constructor-arg>
</bean>
</list>
</constructor-arg>
</bean>
</property>
</bean>
</list>
</constructor-arg>
</bean>
<!--Zulassungsverarbeitungsstelle-->
<bean id="accessDecisionManager"
class="org.springframework.security.access.vote.AffirmativeBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter" />
</list>
</constructor-arg>
</bean>
<!--Definitionsinformationen wie die Zuordnung zwischen URLs, für die Authentifizierung und Berechtigungen erforderlich sind-->
<bean id="securityMetadataSource"
class="org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource">
<constructor-arg index="0">
<util:map id="requestMap" map-class="java.util.LinkedHashMap">
<entry>
<key>
<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
<constructor-arg value="/login" />
</bean>
</key>
<bean class="org.springframework.security.access.SecurityConfig"
factory-method="createList">
<constructor-arg value="permitAll" />
</bean>
</entry>
<entry>
<key>
<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
<constructor-arg value="/**" />
</bean>
</key>
<bean class="org.springframework.security.access.SecurityConfig"
factory-method="createList">
<constructor-arg value="isAuthenticated()" />
</bean>
</entry>
</util:map>
</constructor-arg>
<constructor-arg index="1">
<bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />
</constructor-arg>
</bean>
</beans>
Das Klassendiagramm sieht wie folgt aus.
Um es etwas gröber auszudrücken,
So was.
Mit "FilterChainProxy" als Eingang werden verschiedene "Filter", die nach "SecurityFilterChain" gruppiert sind, der Reihe nach ausgeführt, und "FilterSecurityInterceptor" verarbeitet die Authentifizierung / Autorisierung unmittelbar vor dem geschützten Objekt.
Beim Lesen der Spring Security-Referenz stoße ich häufig auf den Begriff ** sicheres Objekt **.
Dies ist ein Begriff, der von Spring Security definiert wird und sich auf das bezieht, was gesichert ist (oder sein sollte).
Typische Beispiele sind "Webanforderung" und "Ausführung der Methode".
Als ich zum ersten Mal den Namen "FilterSecurityInterceptor" sah, war ich verwirrt über "Ist das" Filter "oder" Interceptor "?"
Diese Klasse implementiert die Filter-Schnittstelle, sodass sie auf den ersten Blick wie Filter aussieht.
Die Antwort, oder besser gesagt, als ich mir die Typhierarchie dieser Klasse ansah, lernte ich die wahre Natur dieser Klasse kennen.
MethodSecurityInterceptor
, dessen AbstractSecurityInterceptor` im selben übergeordneten Element enthalten ist, existiert als Geschwisterklasse.
Das heißt, der "Interceptor" für die Sicherheit von "Filter" ist "FilterSecurityInterceptor". Da "Interceptor" für die Sicherheit der Methodenausführung "MethodSecurityInterceptor" ist, handelt es sich nur um "Interceptor".
Der "FilterSecurityInterceptor" ist sozusagen "der" Interceptor "für den" Filter "durch den" Filter "des" Filters ". vielleicht.
Java Configuration Ab Spring Security 3.2 ist die in Spring 3.1 hinzugefügte Java-Konfiguration verfügbar. Mit der Java-Konfiguration können Sie Einstellungen ähnlich wie Namespaces ohne XML-Datei schreiben.
Durch die Verwendung der Java-Konfiguration kann der Compiler nach einigen Konfigurationsfehlern suchen und das Refactoring wird einfacher.
Ordnerstruktur
|-build.gradle
`-src/main/
|-java/
| `-sample/spring/security/
| `-MySpringSecurityConfig.java
`-webapp/
|-index.jsp
`-WEB-INF/
`-web.xml
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>sample.spring.security.MySpringSecurityConfig</param-value>
</context-param>
</web-app>
MySpringSecurityConfig.java
package sample.spring.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("hoge").password("HOGE").roles("USER");
}
}
index.jsp
bleibt unverändert.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>sample.spring.security.MySpringSecurityConfig</param-value>
</context-param>
</web-app>
Ändern Sie die Einstellung so, dass "AnnotationConfigWebApplicationContext" anstelle von "XmlWebApplicationContext" verwendet wird, das standardmäßig verwendet wurde.
Wenn Sie "
Darüber hinaus kann die von "AnnotationConfigWebApplicationContext" gelesene Konfigurationsklasse angegeben werden, indem "
MySpringSecurityConfig.java
package sample.spring.security;
...
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
...
}
Um Java Configuration for Spring Security zu aktivieren, kommentieren Sie die mit "AnnotationConfigWebApplicationContext" geladene Klasse mit "@ EnableWebSecurity".
Sie können sehen, warum Spring Security aktiviert ist, indem Sie sich die Implementierung dieser Anmerkung ansehen.
EnableWebSecurity.java
...
package org.springframework.security.config.annotation.web.configuration;
...
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
...
@Import({ WebSecurityConfiguration.class,
SpringWebMvcImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
...
}
WebSecurityConfiguration
wird mit @ Import
geladen.
Diese Klasse ist auch eine Konfigurationsklasse, die mit "@ Configuration" versehen ist. </ span>
WebSecurityConfiguration.java
...
package org.springframework.security.config.annotation.web.configuration;
...
import javax.servlet.Filter;
...
@Configuration
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
...
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
...
return webSecurity.build();
}
...
}
Der Wert von "AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME" ist "springSecurityFilterChain". Der Rückgabewert von "webSecurity.build ()" ist "FilterChainProxy", und die Bean wird auf dieselbe Weise registriert wie in XML.
Kommentieren Sie also mit "@ EnableWebSecurity", um Spring Security zu aktivieren.
MySpringSecurityConfig.java
package sample.spring.security;
...
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
...
}
Um bestimmte Einstellungen für Spring Security vorzunehmen, erben Sie zunächst die Klasse "WebSecurityConfigurerAdapter".
Der "WebSecurityConfigurerAdapter" dient standardmäßig zum Erstellen einer einfachen "SecurityFilterChain". Durch Erben dieser Klasse und Überschreiben von Methoden wie "configure (HttpSecurity)" können Sie die zu erstellende "SecurityFilterChain" anpassen.
Die als Argument empfangene "HttpSecurity" entspricht dem "<http>
vorgenommenen Einstellungen auch mit HttpSecurity
vorgenommen werden.
Die obige Implementierung hat dieselbe Bedeutung wie das folgende XML. (* Das Abmelden wird weggelassen, da "WebSecurityConfigurerAdapter" automatisch intern registriert wird.)
applicaitonContext.xml
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login />
<sec:logout />
</sec:http>
Die Methode "authorizeRequests ()" ist die Methode, die die Einstellung von "
Wenn Sie die Einstellung von und ()
ein.
Die Methode and ()
gibt HttpSecurity
zurück, sodass Sie mit der nächsten Konfiguration fortfahren können, ohne die Methodenkette zu unterbrechen.
formLogin ()
aktiviert, wie der Name schon sagt, die Formularauthentifizierung.
MySpringSecurityConfig.java
package sample.spring.security;
...
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
...
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("hoge").password("HOGE").roles("USER");
}
}
"AuthenticationManagerBuilder" ist eine Unterstützungsklasse zum Definieren der folgenden Klassen von "AuthenticationManager". Sie können "UserDetailsService" usw. mithilfe der Methodenkette wie in der obigen Implementierung definieren.
Übrigens können Sie eine Methode deklarieren, die eine Bean direkt definiert, ohne "AuthenticationManagerBuilder" zu verwenden.
Bei der Einstellung in der Bean-Definition
package sample.spring.security;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
...
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
...
@Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("hoge").password("HOGE").roles("USER").build());
return manager;
}
}
Es scheint ungefähr, dass es im folgenden Ablauf initialisiert wird.
Wenn Ihr AP-Server Servlet 3.0 oder höher ist, können Sie Spring Security ohne web.xml verwenden.
Ordnerstruktur
|-build.gradle
`-src/main/
|-java/
| `-sample/spring/security/
| |-MySpringSecurityInitializer.java
| `-MySpringSecurityConfig.java
`-web/
`-index.jsp
MySpringSecurityInitializer.java
package sample.spring.security;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class MySpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public MySpringSecurityInitializer() {
super(MySpringSecurityConfig.class);
}
}
MySpringSecurityConfig.java
und index.jsp
sind die gleichen wie die vorherigen, daher werde ich sie weglassen.
Ich habe "web.xml" entfernt und stattdessen eine Klasse namens "MySpringSecurityInitializer" hinzugefügt.
Diese Klasse wird durch Erben von "AbstractSecurityWebApplicationInitializer" erstellt. Implementieren Sie dann den Konstruktor so, dass das Objekt "Class" der Java-Konfigurationsklasse ("MySpringSecurityConfig") an die übergeordnete Klasse übergeben wird.
Dadurch werden alle Einstellungen entfernt, die in "web.xml" vorgenommen wurden.
Zur Realisierung dieser Funktion werden mehrere in Servlet 3.0 hinzugefügte Mechanismen verwendet. Mal sehen, wie die Einstellung ohne "web.xml" realisiert wird.
ServletContainerInitializer
AbstractSecurityWebApplicationInitializer
implementiert eine Schnittstelle namens WebApplicationInitializer
.
Das Javadoc für diesen WebApplicationInitializer lautet:
WebApplicationInitializer.java
/**
* ...
*
* <p>Implementations of this SPI will be detected automatically by {@link
* SpringServletContainerInitializer}, which itself is bootstrapped automatically
* by any Servlet 3.0 container. See {@linkplain SpringServletContainerInitializer its
* Javadoc} for details on this bootstrapping mechanism.
* ...
*/
public interface WebApplicationInitializer {
Es scheint, dass die Klasse, die diese Schnittstelle implementiert, automatisch von der Klasse "SpringServletContainerInitializer" in der Umgebung von Servlet 3.0 oder höher geladen wird.
Sehen Sie sich die Implementierung von SpringServletContainerInitializer
an.
SpringServletContainerInitializer.java
package org.springframework.web;
...
import javax.servlet.ServletContainerInitializer;
import javax.servlet.annotation.HandlesTypes;
...
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
...
Es implementiert "ServletContainerInitializer" und ist mit "@ HandlesTypes" versehen. Beide wurden in Servlet 3.0 hinzugefügt.
Die Methode onStartup (Set <Class <? >>, ServletContext)
dieser Klasse wird ausgeführt, wenn der Servlet-Container gestartet wird.
Im ersten Argument der Methode wird die durch "@ HandlesTypes" angegebene Klasse [^ 1], die sich auf "Class" bezieht, automatisch vom Container durchsucht und übergeben.
Im Fall von "SpringServletContainerInitializer" wird "WebApplicationInitializer" angegeben, sodass die Klasse, die diese Schnittstelle implementiert, vom Servlet-Container durchsucht und übergeben wird.
[^ 1]: Für Schnittstellen die Implementierungsklasse, für abstrakte / konkrete Klassen, die Klassen und Unterklassen und für Anmerkungen die mit Anmerkungen versehene Klasse.
Wenn die Methode "onStartup ()" des "SpringServletContainerInitializer" ausgeführt wird, wird eine Instanz der Klasse erstellt, die den "WebApplicationInitializer" implementiert, und die Methode "onStartup (ServletContext)" des "WebApplicationInitializer" wird ausgeführt.
AbstractSecurityWebApplicationInitializer Die Methode "onStartup (ServletContext)" von "AbstractSecurityWebApplicationInitializer" hat die folgende Implementierung.
AbstractSecurityWebApplicationInitializer.java
package org.springframework.security.web.context;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.ServletContext;
...
import org.springframework.context.ApplicationContext;
...
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.AbstractContextLoaderInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
...
public abstract class AbstractSecurityWebApplicationInitializer
implements WebApplicationInitializer {
...
public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";
...
public final void onStartup(ServletContext servletContext) throws ServletException {
beforeSpringSecurityFilterChain(servletContext);
if (this.configurationClasses != null) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext(); ★
rootAppContext.register(this.configurationClasses);
servletContext.addListener(new ContextLoaderListener(rootAppContext)); ★
}
if (enableHttpSessionEventPublisher()) {
servletContext.addListener(
"org.springframework.security.web.session.HttpSessionEventPublisher");
}
servletContext.setSessionTrackingModes(getSessionTrackingModes());
insertSpringSecurityFilterChain(servletContext);
afterSpringSecurityFilterChain(servletContext);
}
...
private void insertSpringSecurityFilterChain(ServletContext servletContext) {
String filterName = DEFAULT_FILTER_NAME;
DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(
filterName); ★
String contextAttribute = getWebApplicationContextAttribute();
if (contextAttribute != null) {
springSecurityFilterChain.setContextAttribute(contextAttribute);
}
registerFilter(servletContext, true, filterName, springSecurityFilterChain);
}
...
}
Hier und da gibt es einige bekannte Klassen ...
Kurz gesagt, die Einstellungen, die in "web.xml" vorgenommen wurden, werden in dieser Implementierung vorgenommen.
Es wird durch den folgenden Ablauf initialisiert. (Wie üblich gibt es einige Teile, die zur Vereinfachung nicht streng sind)
Recommended Posts