Je me rends compte que la sécurité Spring s'appuie sur une chaîne de filtres, qui interceptera la demande, détectera (l'absence) d'authentification, redirigera vers le point d'entrée d'authentification ou transmettra la demande au service d'autorisation, et finira par laisser la demande frapper le servlet ou lancer une exception de sécurité (non authentifié ou non autorisé). DelegatingFitlerProxy colle ces filtres ensemble. Pour effectuer leurs tâches, ces filtres accèdent aux services tels que UserDetailsService et AuthenticationManager .
Les filtres clés de la chaîne sont (dans l'ordre)
- SecurityContextPersistenceFilter (restaure l'authentification à partir de JSESSIONID)
- UsernamePasswordAuthenticationFilter (effectue l'authentification)
- ExceptionTranslationFilter (intercepter les exceptions de sécurité de FilterSecurityInterceptor)
- FilterSecurityInterceptor (peut lever des exceptions d'authentification et d'autorisation)
Je ne sais pas comment ces filtres sont utilisés. Est-ce que pour le formulaire de connexion fourni par le printemps, UsernamePasswordAuthenticationFilter n'est utilisé que pour / login , et les derniers filtres ne le sont pas? L' élément d'espace de noms form-login configure-t-il automatiquement ces filtres? Est-ce que chaque demande (authentifiée ou non) atteint FilterSecurityInterceptor pour une URL sans connexion?
Que faire si je souhaite sécuriser mon API REST avec un jeton JWT , qui est récupéré lors de la connexion? Je dois configurer deux http
balises de configuration d'espace de noms , des droits? Un pour / login avec UsernamePasswordAuthenticationFilter
, et un autre pour les URL REST, avec custom JwtAuthenticationFilter
.
La configuration de deux http
éléments en crée- springSecurityFitlerChains
t-elle deux ? Est UsernamePasswordAuthenticationFilter
-il désactivé par défaut, jusqu'à ce que je déclare form-login
? Comment puis-je remplacer SecurityContextPersistenceFilter
par un filtre qui obtiendra Authentication
de l'existant JWT-token
plutôt que JSESSIONID
?
la source
Réponses:
La chaîne de filtres de sécurité Spring est un moteur très complexe et flexible.
En regardant la documentation actuelle de la version stable 4.2.1 , section 13.3 Ordre des filtres, vous pouvez voir toute l'organisation des filtres de la chaîne de filtres:
Maintenant, je vais essayer de poursuivre vos questions une par une:
Une fois que vous avez configuré une
<security-http>
section, pour chacune, vous devez au moins fournir un mécanisme d'authentification. Cela doit être l'un des filtres qui correspondent au groupe 4 dans la section 13.3 Ordre des filtres de la documentation Spring Security que je viens de citer.C'est l'élément de sécurité minimum valide: http qui peut être configuré:
Juste en faisant cela, ces filtres sont configurés dans le proxy de la chaîne de filtres:
Remarque: je les reçois en créant un simple RestController qui @Autowires le FilterChainProxy et renvoie son contenu:
Ici, nous avons pu voir qu'en déclarant simplement l'
<security:http>
élément avec une configuration minimale, tous les filtres par défaut sont inclus, mais aucun d'entre eux n'est de type Authentification (4ème groupe dans la section 13.3 Trier les filtres). Cela signifie donc en fait qu'en déclarant simplement l'security:http
élément, SecurityContextPersistenceFilter, ExceptionTranslationFilter et FilterSecurityInterceptor sont auto-configurés.En fait, un mécanisme de traitement d'authentification doit être configuré, et même les beans d'espace de noms de sécurité traitant des revendications pour cela, lançant une erreur au démarrage, mais il peut être contourné en ajoutant un attribut entry-point-ref dans
<http:security>
Si j'ajoute un élément
<form-login>
de base à la configuration, de cette façon:Maintenant, le filterChain sera comme ceci:
Maintenant, ces deux filtres org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter et org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter sont créés et configurés dans FilterChainProxy.
Alors, maintenant, les questions:
Oui, il est utilisé pour essayer de terminer un mécanisme de traitement de connexion au cas où la demande correspond à l'url UsernamePasswordAuthenticationFilter. Cette URL peut être configurée ou même modifiée son comportement pour correspondre à chaque demande.
Vous pouvez également avoir plus d'un mécanisme de traitement d'authentification configuré dans le même FilterchainProxy (tel que HttpBasic, CAS, etc.).
Non, l'élément form-login configure le UsernamePasswordAUthenticationFilter, et si vous ne fournissez pas d'URL de page de connexion, il configure également org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter, qui se termine par une simple connexion générée automatiquement page.
Les autres filtres sont auto-configurés par défaut simplement en créant un
<security:http>
élément sanssecurity:"none"
attribut.Chaque requête doit l'atteindre, car c'est l'élément qui vérifie si la requête a le droit d'atteindre l'url demandée. Mais certains des filtres traités auparavant peuvent arrêter le traitement de la chaîne de filtres tout simplement ne pas appeler
FilterChain.doFilter(request, response);
. Par exemple, un filtre CSRF peut arrêter le traitement de la chaîne de filtres si la demande n'a pas le paramètre csrf.Non, vous n'êtes pas obligé de faire de cette façon. Vous pouvez déclarer les deux
UsernamePasswordAuthenticationFilter
et leJwtAuthenticationFilter
dans le même élément http, mais cela dépend du comportement concret de chacun de ces filtres. Les deux approches sont possibles, et celle à choisir dépend finalement de ses propres préférences.Oui c'est vrai
Oui, vous pouvez le voir dans les filtres soulevés dans chacune des configurations que j'ai postées
Vous pouvez éviter SecurityContextPersistenceFilter, en configurant simplement la stratégie de session dans
<http:element>
. Configurez simplement comme ceci:<security:http create-session="stateless" >
Ou, dans ce cas, vous pouvez l'écraser avec un autre filtre, de cette façon à l'intérieur de l'
<security:http>
élément:ÉDITER:
Cela dépend finalement de l'implémentation de chaque filtre lui-même, mais c'est vrai que ces derniers filtres d'authentification au moins sont capables d'écraser toute authentification antérieure éventuellement faite par les filtres précédents.
Mais cela n'arrivera pas nécessairement. J'ai des cas de production dans des services REST sécurisés où j'utilise une sorte de jeton d'autorisation qui peut être fourni à la fois en tant qu'en-tête Http ou dans le corps de la requête. Je configure donc deux filtres qui récupèrent ce jeton, dans un cas à partir de l'en-tête Http et l'autre à partir du corps de la requête de la propre requête de repos. Il est vrai que si une requête http fournit ce jeton d'authentification à la fois comme en-tête Http et à l'intérieur du corps de la requête, les deux filtres essaieront d'exécuter le mécanisme d'authentification en le déléguant au gestionnaire, mais cela pourrait être facilement évité de simplement vérifier si la requête est déjà authentifié juste au début de la
doFilter()
méthode de chaque filtre.Avoir plus d'un filtre d'authentification est lié au fait d'avoir plus d'un fournisseur d'authentification, mais ne le forcez pas. Dans le cas que j'ai exposé auparavant, j'ai deux filtres d'authentification mais je n'ai qu'un seul fournisseur d'authentification, car les deux filtres créent le même type d'objet d'authentification, donc dans les deux cas, le gestionnaire d'authentification le délègue au même fournisseur.
Et à l'opposé de cela, j'ai aussi un scénario dans lequel je publie un seul UsernamePasswordAuthenticationFilter mais les informations d'identification de l'utilisateur peuvent toutes deux être contenues dans DB ou LDAP, j'ai donc deux fournisseurs de support UsernamePasswordAuthenticationToken, et AuthenticationManager délègue toute tentative d'authentification du filtre aux fournisseurs Secuentially pour valider les informations d'identification.
Donc, je pense qu'il est clair que ni le nombre de filtres d'authentification ne détermine le nombre de fournisseurs d'authentification ni le nombre de fournisseurs ne déterminent le nombre de filtres.
Je n'ai pas examiné attentivement ce filtre auparavant, mais après votre dernière question, j'ai vérifié sa mise en œuvre et, comme d'habitude au printemps, presque tout pourrait être configuré, étendu ou écrasé.
Les SecurityContextPersistenceFilter délégués dans une SecurityContextRepository mise en œuvre de la recherche pour la SecurityContext. Par défaut, un HttpSessionSecurityContextRepository est utilisé, mais cela peut être modifié à l'aide de l'un des constructeurs du filtre. Il peut donc être préférable d'écrire un SecurityContextRepository qui correspond à vos besoins et de le configurer simplement dans SecurityContextPersistenceFilter, en faisant confiance à son comportement prouvé plutôt que de commencer à tout faire à partir de zéro.
la source
No qualifying bean of type 'org.springframework.security.web.FilterChainProxy' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Non,
UsernamePasswordAuthenticationFilter
étendAbstractAuthenticationProcessingFilter
, et cela contient unRequestMatcher
, cela signifie que vous pouvez définir votre propre url de traitement, ce filtre ne gère que lesRequestMatcher
correspondances à l'url de la demande, l'URL de traitement par défaut est/login
.Les filtres ultérieurs peuvent toujours gérer la demande, si le
UsernamePasswordAuthenticationFilter
fichier s'exécutechain.doFilter(request, response);
.Plus de détails sur les core fitlers
UsernamePasswordAuthenticationFilter
est créé par<form-login>
, il s'agit d' alias de filtre standard et de classementCela dépend de la réussite des fitlers avant, mais
FilterSecurityInterceptor
c'est normalement le dernier fitler.Oui, chaque fitlerChain a un
RequestMatcher
, si leRequestMatcher
correspond à la demande, la demande sera gérée par les fitler dans la chaîne fitler.La valeur par défaut
RequestMatcher
correspond à toutes les requêtes si vous ne configurez pas le modèle, ou vous pouvez configurer l'url spécifique (<http pattern="/rest/**"
).Si vous voulez en savoir plus sur les fitlers, je pense que vous pouvez vérifier le code source dans Spring Security.
doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
la source
Spring Security est un framework basé sur des filtres, il plante un WALL (HttpFireWall) avant votre application en termes de filtres proxy ou de beans gérés par spring. Votre demande doit passer par plusieurs filtres pour atteindre votre API.
Séquence d'exécution dans Spring Security
WebAsyncManagerIntegrationFilter
Fournit une intégration entre SecurityContext et WebAsyncManager de Spring Web.SecurityContextPersistenceFilter
Ce filtre ne s'exécutera qu'une fois par demande, remplit le SecurityContextHolder avec les informations obtenues à partir du SecurityContextRepository configuré avant la demande et le stocke de nouveau dans le référentiel une fois la demande terminée et en effaçant le détenteur du contexte.La demande est vérifiée pour la session existante. Si une nouvelle demande, SecurityContext sera créée, sinon si la demande a une session, le contexte de sécurité existant sera obtenu à partir du référentiel .
HeaderWriterFilter
Filtrer l'implémentation pour ajouter des en-têtes à la réponse actuelle.LogoutFilter
Si l'URL de la requête est/logout
(pour la configuration par défaut) ou si l'URL de la requête estRequestMatcher
configurée dansLogoutConfigurer
alorsLogoutConfigurer
/
ou l' URL de réussite de déconnexion configurée ou appelle logoutSuccessHandler configuré.UsernamePasswordAuthenticationFilter
HTTP POST
) par défaut/login
ou correspond à la.loginProcessingUrl()
configuration,FormLoginConfigurer
alorsUsernamePasswordAuthenticationFilter
tente l'authentification.usernameParameter(String)
,passwordParameter(String)
..loginPage()
remplace les valeurs par défautAuthentication
objet (UsernamePasswordAuthenticationToken
ou toute implémentation deAuthentication
dans le cas de votre filtre d'authentification personnalisé) est créé.authenticationManager.authenticate(authToken)
sera invoquéAuthenticationProvider
méthodes d'authentification essayant tous les fournisseurs d' authentification et vérifie l'un dessupports
objets authToken / authentication du fournisseur d' authentification, le fournisseur d' authentification prenant en charge sera utilisé pour l'authentification. et renvoie l'objet d'authentification en cas d'authentification réussie, sinonAuthenticationException
.authenticationSuccessHandler
sera appelée, ce qui redirigera vers l'URL cible configurée (la valeur par défaut est/
)SecurityContextHolderAwareRequestFilter
, si vous l'utilisez pour installer un HttpServletRequestWrapper prenant en charge Spring Security dans votre conteneur de servletAnonymousAuthenticationFilter
Détecte s'il n'y a pas d'objet d'authentification dans SecurityContextHolder, si aucun objet d'authentification n'a été trouvé, créeAuthentication
object (AnonymousAuthenticationToken
) avec l'autorisation accordéeROLE_ANONYMOUS
. IciAnonymousAuthenticationToken
facilite l'identification des demandes ultérieures des utilisateurs non authentifiés.ExceptionTranslationFilter
, pour intercepter toutes les exceptions Spring Security afin qu'une réponse d'erreur HTTP puisse être renvoyée ou qu'un AuthenticationEntryPoint approprié puisse être lancéFilterSecurityInterceptor
Il y aura ce
FilterSecurityInterceptor
qui arrive presque en dernier dans la chaîne de filtrage qui obtient l'objet d'authentificationSecurityContext
et obtient la liste des autorités accordées (rôles accordés) et il prendra la décision d'autoriser ou non cette demande à atteindre la ressource demandée, la décision est prise en faisant correspondre avec le autoriséAntMatchers
configuré dansHttpSecurityConfiguration
.Considérez les exceptions 401-UnAuthorized et 403-Forbidden. Ces décisions seront prises au dernier dans la chaîne de filtrage
Remarque: l' utilisateur demande des flux non seulement dans les filtres ci - dessus mentionnés, mais il y a les autres filtres trop non représentés ici (.
ConcurrentSessionFilter
,RequestCacheAwareFilter
,SessionManagementFilter
...)Ce sera différent lorsque vous utilisez votre filtre auth personnalisé au lieu de
UsernamePasswordAuthenticationFilter
.Ce sera différent si vous configurez le filtre d'authentification JWT et que vous l'omettez,
.formLogin() i.e, UsernamePasswordAuthenticationFilter
ce sera un cas entièrement différent.Juste pour référence. Filtres dans spring-web et spring-security
Remarque: référez - vous au nom du package dans la photo , car il existe d'autres filtres d'orm et mon filtre implémenté personnalisé.
Vous pouvez également vous référer au
moyen le plus courant d'authentifier une application Web moderne?
différence entre l'authentification et l'autorisation dans le contexte de Spring Security?
la source