Histoire de certification / d'autorisation Histoire Remember-Me Histoire CSRF Histoire de gestion de session Parler de l'en-tête de réponse Histoire de la sécurité de la méthode Histoire CORS L'histoire de Run-As L'histoire d'ACL Test story Parlez de la coopération avec MVC et Boot
Édition supplémentaire Ce que Spring Security peut et ne peut pas faire
Java 1.8.0_xxx
Tomcat 8.0.35
Gradle 3.2.1
OS Windows 10
Un des projets de Spring. Un cadre qui ajoute principalement des fonctionnalités de sécurité aux applications Web.
Il offre une protection contre une variété d'attaques bien connues telles que CSRF et les attaques de fixation de session.
Hello World Ici est écrit dans un peu plus d'ordre pour l'annonce. Cela peut être plus facile à comprendre si vous le lisez avec la diapositive (je pense qu'elle n'a été écrite que sur la diapositive).
Structure des dossiers
|-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>
Générez un fichier war (spring-security-sample.war
) avec gradle war
et déployez-le sur Tomcat.
Une fois le déploiement terminé, ouvrez http: // localhost: 8080 / spring-security-sample
dans votre navigateur.
Un mystérieux écran de connexion s'affiche.
Saisissez respectivement «hoge» et «HOGE» dans User et Password et cliquez sur le bouton «Login».
ʻLe contenu de index.jsp` est affiché.
Enfin, cliquez sur le bouton déconnexion
.
La déconnexion est terminée et vous revenez à l'écran de connexion.
build.gradle
compile 'org.springframework.security:spring-security-web:4.2.1.RELEASE'
compile 'org.springframework.security:spring-security-config:4.2.1.RELEASE'
Dans la configuration minimale, vous pouvez ajouter spring-security-web
et spring-security-config
comme dépendances cela semble bon .RELEASE / reference / htmlsingle / #gradle).
spring-security-web
Il contient du code lié à "Filtre" et aux applications Web. Si vous avez besoin d'une authentification Web ou d'un contrôle d'accès basé sur les URL, vous avez besoin de ce module. Le paquet principal est ʻorg.springframework.security.web`
spring-security-config
Il contient du code pour analyser l'espace de noms utilisé pour écrire des définitions en xml et du code pour la configuration Java. Ce module est requis pour la configuration XML et les configurations Java. Le paquet principal est ʻorg.springframework.security.config` Les classes incluses ici ne sont pas utilisées directement par l'application.
web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
En enregistrant ContextLoaderListener
comme écouteur, le conteneur Spring (ʻApplicationContext`) est initialisé.
ʻSi vous ne spécifiez pas ce qu'il faut utiliser pour la classe ApplicationContext,
XmlWebApplicationContext est utilisé par défaut. Il est défini dans ʻorg / springframework / web / context / ContextLoader.properties
de spring-web-x.x.x.RELEASE.jar
comme suit, et ContextLoaderListener
est chargé lorsque le conteneur de servlet est initialisé.
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
charge WEB-INF / applicationContext.xml
comme fichier de configuration par défaut.
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` lui-même est un fichier de configuration standard pour la définition de Spring Bean, pas un fichier de configuration spécial pour Spring Security.
En chargeant http: // www.springframework.org / schema / security
avec xmlns
, vous pouvez utiliser la balise pour Spring Security (dans la référence, utilisez cette balise dédiée à Spring Security * Nous l'appelons * namespace **).
Vous pouvez utiliser cette balise pour configurer les paramètres de Spring Security sur ce fichier.
Les paramètres ci-dessus définissent approximativement les éléments suivants:
/ login
( permitAll
)/ **
) doit être authentifié (ʻisAuthenticated () ) --Comment se connecter au formulaire --Autoriser la déconnexion --Définissez un utilisateur avec le rôle
ROLE_USER avec name =
hoge, password =
HOGE` comme information utilisateurLes étiquettes individuelles seront décrites un peu plus en détail ci-dessous.
<http>
Lorsque vous définissez la balise <http>
, certains beans sont automatiquement enregistrés dans le conteneur.
Parmi eux, les deux classes suivantes sont des beans importants.
FilterChainProxy
SecurityFilterChain
FilterChainProxy
est enregistré dans le conteneur avec le nom du bean "springSecurityFilterChain"
. </ span>
Cette classe est la passerelle vers le traitement Spring Security.
SecurityFilterChain
est juste une interface en soi, et DefaultSecurityFilterChain
est enregistré dans le conteneur en tant que classe d'implémentation.
Comme son nom l'indique, «SecurityFilterChain» est une chaîne de «javax.servlet.Filter» qui a une fonction de sécurité et contient plusieurs «Filter».
Spring Security réalise la fonction de sécurité en utilisant Filter
.
Comme vous pouvez le voir à partir du nom FilterChainProxy
, la classe elle-même ne fait rien.
Un traitement spécifique est délégué aux Filter
s de la SecurityFilterChain
.
<intercept-url>
Les conditions (contrôle d'accès) requises pour l'accès sont définies pour chaque modèle d'URL.
L'attribut pattern
peut être décrit dans ant path format.
Dans l'attribut ʻaccess, spécifiez les conditions requises pour accéder à l'URL spécifiée dans l'attribut
pattern. «permitAll» signifie autoriser tous les accès (aucune authentification requise). Et ʻisAuthenticated ()
signifie autoriser l'accès s'il est authentifié (connecté).
L'attribut ʻaccess` est décrit en utilisant le propre langage d'expression de Spring appelé Spring Expression Language (SpEL).
<form-login>
Définit que l'authentification par formulaire est requise.
En cas d'erreur d'authentification, vous serez redirigé vers / login
par défaut.
Par défaut, accéder à / login
vous amènera à une simple page de connexion fournie par Spring Security.
Cette page de connexion par défaut est générée par DefaultLoginPageGeneratingFilter
dans spring-security-web-x.x.x.RELEASE.jar
.
<logout>
En ajoutant cette balise, vous pourrez vous déconnecter.
Par défaut, une requête POST à / logout
entraînera une déconnexion.
<authentication-manager>
ʻDéfinir AuthenticationManager comme un bean. ʻAuthenticationManager
est une classe qui exécute le traitement d'authentification et doit être définie.
ʻAuthenticationManager lui-même est une interface, et la classe d'implémentation utilise
ProviderManager.
ProviderManager lui-même n'effectue pas de traitement d'authentification spécifique, mais délègue le traitement d'authentification à ʻAuthenticationProvider
, qui sera décrit plus loin.
<authentication-provider>
ʻDefine AutheticationProvider` comme un bean. Cette interface fournit un traitement d'authentification spécifique en fonction du type d'authentification.
Par exemple, la classe qui fournit le traitement d'authentification LDAP est comme LdapAuthenticationProvider
.
Si vous déclarez cette balise, DaoAuthenticationProvider
est enregistré dans le conteneur.
Cette classe obtient les informations utilisateur de ʻUserDetailsService` et effectue le traitement d'authentification.
<user-service>
ʻEnregistrez UserDetailsService comme un bean. Cette interface offre la possibilité de récupérer des informations détaillées sur l'utilisateur (ʻUserDetails
).
La déclaration de cette balise enregistrera ʻInMemoryUserDetailsManager` dans le conteneur. Comme son nom l'indique, cette classe contient les informations utilisateur en mémoire. Pour ainsi dire, il s'agit d'une mise en œuvre temporaire pour le contrôle de fonctionnement.
<user>
ʻDéfinir une instance de UserDetails`. Cette interface définit la méthode Getter, etc. pour accéder aux informations utilisateur détaillées.
La déclaration de cette balise crée une instance de la classe ʻUser`.
Les attributs «nom», «mot de passe», «autorités» vous permettent de spécifier des noms, des mots de passe et des autorisations pour identifier les utilisateurs.
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>
Définissez DelegatingFilterProxy
comme filtre de servlet dans web.xml
.
A ce moment, <nom-filtre>
est défini avec le nom " springSecurityFilterChain "
.
Désormais, Spring Security sera appliqué lors de l'accès à l'URL définie par `
DelegatingFilterProxy
obtient un bean qui implémente javax.servlet.Filter
à partir du conteneur Spring en utilisant le nom défini dans son propre<nom-filtre>
.
Et c'est un filtre de servlet qui délègue simplement le traitement à ce bean.
Ici, «springSecurityFilterChain» est spécifié pour «FilterChainProxy
qui est automatiquement enregistré dans le conteneur lorsque vous utilisez la balise <http>
dans ʻapplicationContext.xml`. Je le fais.
En d'autres termes, DelegatingFilterProxy
est responsable du pontage du filtre de servlet et de Spring Security ( FilterChainProxy
).
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>
Par défaut, les mesures CSRF sont activées. Par conséquent, lors de l'envoi d'une demande, il est nécessaire de transmettre un jeton pour les contre-mesures CSRF ensemble.
Les valeurs de jeton et les noms de paramètres sont stockés dans la portée de la requête en tant que _csrf
.
Une explication plus détaillée des mesures du CSRF sera fournie ultérieurement. .. ..
Résumez la façon dont le processus se déroule dans les coulisses entre le démarrage du serveur et la connexion.
J'utilise un diagramme de séquence, mais ce n'est pas mal car il ne suit pas la notation UML stricte pour plus de clarté.
Bien que ce ne soit pas en partie strict, je pense que le processus d'initialisation → d'authentification est effectué dans l'atmosphère suivante.
ContextLoaderListener
, qui est enregistré comme Listener
dans web.xml
, est exécuté.XmlWebApplicationContext
est créée et / WEB-INF / applicationContext.xml
est chargé.<http>
enregistre une instance de FilterChainProxy
avec le conteneur Spring avec le nom" "springSecurityFilterChain"
.DelegateFilterProxy
, qui est enregistré comme Filter
dans web.xml
, est généré par le conteneur de servlet.DelegateFilterProxy
est appelé pour récupérer le bean du conteneur Spring avec son propre nom ("springSecurityFilterChain"
) ( FilterChainProxy
est obtenu).FilterChainProxy
.Ce n'est pas non plus strict, mais je pense que le flux lorsque vous êtes redirigé vers l'écran de connexion lorsque vous y accédez sans vous connecter est le suivant.
FilterSecurityInterceptor
appelle le processus d'authentification de ʻAuthenticationManager`. exécute le processus d'authentification, mais lance ʻAuthenticationException
parce qu'il n'est pas authentifié.LoginUrlAuthenticationEntryPoint
vous redirige vers l'écran de connexion.Le flux entre immédiatement après avoir été redirigé vers / login
par LoginUrlAuthenticationEntryPoint
pour se connecter en entrant le nom d'utilisateur et le mot de passe.
DefaultLoginPageGeneratingFilter
générera l'écran de connexion par défaut./ login
, ʻUsernamePasswordAuthenticationFilter délègue le processus d'authentification à ʻAuthenticationManager
.ProviderManager
, qui est une classe d'implémentation de ʻAuthenticationManager, délègue le processus d'authentification à ʻAuthenticationProvider
.DaoAuthenticationProvider
, qui est une classe d'implémentation de ʻAuthenticationProvider, acquiert les informations utilisateur (ʻUserDetails
) de ʻUserDetailsService` et exécute le processus d'authentification. délègue le traitement de l'authentification réussie à ʻAuthenticationSuccessFilter
.HttpSession
.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>
L'espace de noms (balise dédiée) enregistre automatiquement les différents beans nécessaires pour exécuter Spring Security dans le conteneur. Grâce à cela, les paramètres de Spring Security sont très simples à écrire.
Cependant, lorsqu'il devient nécessaire d'étendre la fonction d'authentification, il devient important de comprendre quels types de beans sont enregistrés dans les coulisses et quel type de relation ils entretiennent.
Pour comprendre cela, réécrivons le fichier de configuration créé dans Hello World sans utiliser d'espace de noms.
Cependant, je ne ferai pas de mon mieux pour que ce soit exactement le même que le paramètre dans l'espace de noms, mais pour reproduire la série de processus de connexion vu dans Hello World. Par conséquent, certaines définitions de bean sont omises.
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>
<!--Initialiser / effacer SecurityContextHolder-->
<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>
<!--Se déconnecter-->
<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>
<!--Authentification de connexion-->
<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>
<!--Générer la page de connexion par défaut-->
<bean id="defaultLoginPageGeneratingFilter"
class="org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter">
<constructor-arg ref="usernamePasswordAuthenticationFilter" />
<property name="authenticationUrl" value="/login" />
</bean>
<!--Gestionnaire d'exceptions d'authentification-->
<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>
<!--Traitement d'authentification / d'autorisation-->
<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>
<!--Corps de traitement d'authentification-->
<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>
<!--Organisme de traitement des autorisations-->
<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>
<!--Informations de définition telles que le mappage entre les URL qui nécessitent une authentification et des autorisations-->
<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>
Le diagramme de classes ressemble à ce qui suit.
Pour le dire un peu plus grossièrement,
Comme ça.
Avec FilterChainProxy
comme entrée, divers Filter
s regroupés par SecurityFilterChain
sont exécutés dans l'ordre, et FilterSecurityInterceptor
traite l'authentification / autorisation juste avant l'objet protégé.
En lisant la référence Spring Security, je rencontre souvent le terme ** objet sécurisé **.
Il s'agit d'un terme défini par Spring Security et fait référence à ce qui est (ou devrait être) sécurisé.
Des exemples typiques sont "requête Web" et "exécution de méthode".
Quand j'ai vu pour la première fois le nom de «FilterSecurityInterceptor», j'étais confus quant à savoir si c'était «Filter» ou «Interceptor».
Cette classe implémente l'interface Filter
, donc cela ressemble à Filter
à première vue.
La réponse, ou plutôt, quand j'ai regardé la hiérarchie des types de cette classe, j'ai appris à connaître la vraie nature de cette classe.
ʻMethodSecurityInterceptor, qui a AbstractSecurityInterceptor
comme même parent, existe en tant que classe sœur.
Autrement dit, ʻInterceptor pour la sécurité de
Filterest
FilterSecurityInterceptor, Puisque ʻInterceptor
pour la sécurité de l'exécution de la méthode est MethodSecurityInterceptor
, ce ne sont que ʻInterceptor`.
FilterSecurityInterceptor
est, pour ainsi dire," ʻInterceptor pour
Filterby
Filter of
Filter`". peut être.
Java Configuration À partir de Spring Security 3.2, la configuration Java ajoutée dans Spring 3.1 est disponible. La configuration Java vous permet d'écrire des paramètres similaires aux espaces de noms sans fichier XML.
En utilisant la configuration Java, il y a des avantages que le compilateur vérifie certaines erreurs de configuration et que la refactorisation sera plus facile.
Structure des dossiers
|-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` n'a pas changé.
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>
Modifiez le paramètre pour utiliser ʻAnnotationConfigWebApplicationContext au lieu de
XmlWebApplicationContext`, qui était utilisé par défaut.
Si vous définissez <context-param>
avec le nom contextClass
, ContextLoaderListener
utilisera la classe spécifiée ici comme conteneur.
De plus, la classe de configuration lue par ʻAnnotationConfigWebApplicationContext peut être spécifiée en définissant
avec le nom
contextConfigLocation`.
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 {
...
}
Pour activer la configuration Java pour Spring Security, annotez la classe chargée avec ʻAnnotationConfigWebApplicationContext avec
@ EnableWebSecurity`.
Vous pouvez voir pourquoi Spring Security est activé en examinant l'implémentation de cette annotation.
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
est chargé en utilisant @ Import
.
Cette classe est également une classe de configuration annotée avec @ Configuration
. </ 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();
}
...
}
ʻLa valeur de AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME est
"springSecurityFilterChain" . La valeur de retour de
webSecurity.build ()est
FilterChainProxy`, et le bean est enregistré de la même manière qu'il a été fait en xml.
Alors, annotez avec @ EnableWebSecurity
pour activer Spring Security.
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();
}
...
}
Pour définir des paramètres spécifiques pour Spring Security, héritez d'abord de la classe WebSecurityConfigurerAdapter
.
Le WebSecurityConfigurerAdapter
est conçu pour construire un SecurityFilterChain
simple par défaut.
En héritant de cette classe et en remplaçant des méthodes telles que configure (HttpSecurity)
, vous pouvez personnaliser la SecurityFilterChain
à construire.
Le HttpSecurity
reçu comme argument correspond à la balise <http>
dans l'espace de noms.
Fondamentalement, les réglages effectués avec <http>
peuvent également être effectués avec HttpSecurity
.
L'implémentation ci-dessus a la même signification que le XML ci-dessous.
(* La déconnexion est omise car WebSecurityConfigurerAdapter
est automatiquement enregistré en interne.)
applicaitonContext.xml
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login />
<sec:logout />
</sec:http>
ʻLa méthode authorizeRequests () est la méthode qui lance le paramétrage de
dans l'espace de noms. Le type de retour de la méthode a été remplacé par une classe appelée ʻExpressionInterceptUrlRegistry
, et une méthode de paramétrage dédiée peut être appelée.
Si vous voulez terminer le réglage de <intercept-url>
et continuer un autre réglage, insérez la méthode ʻand () . La méthode ʻand ()
renvoie HttpSecurity
, vous pouvez donc continuer avec la configuration suivante sans rompre la chaîne de méthodes.
formLogin ()
, comme son nom l'indique, active l'authentification par formulaire.
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 est une classe de support pour définir les classes suivantes, ʻAuthenticationManager
, et vous pouvez définir ʻUserDetailsService` etc. en utilisant une chaîne de méthodes comme dans l'implémentation ci-dessus.
En passant, vous pouvez déclarer une méthode qui définit un bean directement sans utiliser ʻAuthenticationManagerBuilder`.
Lors du réglage dans la définition du bean
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;
}
}
En gros, il semble qu'il soit initialisé dans le flux suivant.
doBuild ()
).
Si vous souhaitez connaître le flux exact, veuillez suivre la mise en œuvre réelle en vous référant à la figure ci-dessous.Si votre serveur AP est Servlet 3.0 ou supérieur, vous pouvez commencer à utiliser Spring Security sans web.xml.
Structure des dossiers
|-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
et ʻindex.jsp` sont les mêmes que les précédents, je vais donc les omettre.
J'ai supprimé web.xml
et ajouté une classe appelée MySpringSecurityInitializer
à la place.
Cette classe est créée en héritant de ʻAbstractSecurityWebApplicationInitializer. Ensuite, implémentez le constructeur pour que l'objet
Class de la classe Java Configuration (
MySpringSecurityConfig`) soit passé à la classe parent.
Cela élimine tous les paramètres définis dans web.xml
.
Plusieurs mécanismes ajoutés dans Servlet 3.0 sont utilisés pour réaliser cette fonction.
Voyons comment le paramètre est réalisé sans web.xml
.
ServletContainerInitializer
ʻAbstractSecurityWebApplicationInitializer implémente une interface appelée
WebApplicationInitializer. Le Javadoc pour ce
WebApplicationInitializer` indique:
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 {
Il semble que la classe qui implémente cette interface est automatiquement chargée par la classe SpringServletContainerInitializer
dans l'environnement de Servlet 3.0 ou supérieur.
Allez voir l'implémentation de SpringServletContainerInitializer
.
SpringServletContainerInitializer.java
package org.springframework.web;
...
import javax.servlet.ServletContainerInitializer;
import javax.servlet.annotation.HandlesTypes;
...
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
...
Il implémente ServletContainerInitializer
et est annoté avec @ HandlesTypes
.
Les deux ont été ajoutés dans Servlet 3.0.
La méthode ʻonStartup (Set <Class <? >>, ServletContext) de cette classe est exécutée au démarrage du conteneur Servlet. Dans le premier argument de la méthode, la classe [^ 1] liée à
Class spécifiée par
@ HandlesTypesest automatiquement recherchée par le conteneur et transmise. Dans le cas de
SpringServletContainerInitializer,
WebApplicationInitializer` est spécifié, donc la classe qui implémente cette interface est recherchée par le conteneur Servlet et transmise.
[^ 1]: Pour les interfaces, la classe d'implémentation, pour les classes abstraites / concrètes, les classes et sous-classes, et pour les annotations, la classe annotée.
Lorsque la méthode ʻonStartup () de
SpringServletContainerInitializer est exécutée, une instance de la classe qui implémente
WebApplicationInitializerest créée et la méthode ʻonStartup (ServletContext)
de WebApplicationInitializer
est exécutée.
AbstractSecurityWebApplicationInitializer
La méthode ʻonStartup (ServletContext) de ʻAbstractSecurityWebApplicationInitializer
a l'implémentation suivante.
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);
}
...
}
Il y a des cours familiers ici et là ...
En bref, les paramètres définis dans web.xml
sont définis dans cette implémentation.
Il est initialisé par le flux suivant. (Comme d'habitude, certaines parties ne sont pas strictes pour simplifier)
Recommended Posts