[JAVA] Découvrez l'architecture de traitement de l'authentification Spring Security

Spring Security semble fonctionner pour une raison quelconque, mais je suis accro à sa personnalisation.Je l'ai donc étudié et résumé à partir de l'idée que si vous connaissez l'architecture, vous pourrez la comprendre d'une manière ou d'une autre.

Recherchez quel type de classe joue quel type de rôle selon le scénario d'authentification par formulaire suivant.

  1. Accédez à une page qui nécessite une authentification sans être authentifié
  2. Redirigé vers l'écran de connexion
  3. Entrez les informations et exécutez le processus de connexion
  4. La connexion est terminée et vous êtes redirigé vers l'écran auquel vous accédiez dans 1.

La version est confirmée dans 5.2.1.RELEASE.

Jusqu'à ce que vous soyez redirigé vers l'écran de connexion

Comment accéder à l'écran de connexion lorsqu'un utilisateur non authentifié accède à une page nécessitant une authentification. Le flux approximatif est le suivant. Cette fois, je n'expliquerai pas le processus de vérification lors de l'accès, mais il commence à partir de l'endroit où ʻAuthenticationException` est lancée.

ログイン遷移.png

ExceptionTranslationFilter

Cause de l'exception qui s'est produite Vérifiez l'exception, et si ʻAuthenticationException est inclus, démarrez le processus d'authentification en utilisant ʻAuthenticationEntryPoint tout en sauvegardant le contenu de la demande dans RequestCache. RequestCache utilise généralement HttpSession pour stocker le contenu de la demande. HttpSessionRequestCache est utilisé. Nous verrons à quoi sert RequestCache plus tard.

AuthenticationEntryPoint

Démarrez le processus d'authentification. Par exemple, LoginUrlAuthenticationEntryPoint redirige vers l'URL de la page de connexion configurée. BasicAuthenticationEntryPoint renvoie une réponse avec un code d'état de 401 et un en-tête avec WWW-Authenticate pour lancer l'authentification de base.

Résumé de la transition de l'écran de connexion

Il est géré par ʻExceptionTranslationFilter, mais vous n'avez pas besoin d'en être conscient car vous n'avez pas à le personnaliser beaucoup. Il est nécessaire de sélectionner et de définir correctement ʻAuthenticationEntryPoint pour savoir comment démarrer l'authentification. Par exemple, si vous souhaitez passer à l'écran de connexion, vous devez définir l'URL de l'écran de connexion à l'aide de LoginUrlAuthenticationEntryPoint, et si vous n'avez pas besoin de démarrer le processus d'authentification en supposant que vous serez authentifié à l'avance comme SSO. Par exemple, utilisez Http403ForbiddenEntryPoint.

Il semble que vous puissiez également définir la classe d'implémentation à utiliser pour la requête en utilisant DelegatingAuthenticationEntryPoint.

Processus d'authentification

Tout d'abord, le flux jusqu'à ce que les informations saisies par l'utilisateur soient reçues et que l'authentification soit OK. C'est à peu près comme suit.

認証.png

AuthenticationManager

ʻAuthenticationManager est en charge de l'authentification. Reçoit un objet ʻAuthentication et renvoie un objet ʻAuthentication si l'authentification est OK. L'argument ʻAuthentication contient uniquement le principal et les informations d'identification requises pour l'authentification, et la valeur de retour ʻAuthentication` contient également des informations telles que les autorités et les détails.

ProviderManager

ʻIl existe ProviderManager comme classe d'implémentation d'AuthenticationManager. Cette classe est utilisée par défaut. Cette classe délègue le processus d'authentification à plusieurs ʻAuthenticationProviders, et si même l'un d'entre eux est OK, l'authentification est réussie. Ce faisant, il est possible de combiner une pluralité de processus d'authentification tels que l'authentification par formulaire à l'aide d'informations stockées dans une base de données et l'authentification par LDAP. Vous pouvez également supprimer les informations d'identification de la valeur de retour ʻAuthentication` pour empêcher la persistance des informations sensibles.

AuthenticationProvider

Authentifier. Si la vérification du mot de passe est requise, utilisez cette classe.

Il existe également une méthode pour déterminer s'il s'agit d'une classe d'implémentation authentifiable de ʻAuthentication. Par exemple, dans le cas d'une authentification par formulaire normale, le processus d'authentification peut être effectué s'il existe un nom d'utilisateur et un mot de passe, mais tous les processus d'authentification ne sont pas suffisants. Par conséquent, la méthode supports (Class <?> Authentication)` est utilisée pour déterminer si le processus d'authentification peut être effectué ou non.

Les classes d'implémentation sont fournies pour les méthodes d'authentification générales, vous pouvez donc les utiliser. Cependant, étant donné que la partie qui acquiert les informations utilisateur dépend de la définition de la base de données utilisée par l'application, il existe de nombreux modèles dans lesquels seule cette partie est implémentée.

UserDetailsService

Une interface de traitement de la partie susmentionnée liée à l'acquisition d'informations utilisateur. Il est souvent utilisé en créant une classe d'implémentation pour cette interface et en la définissant sur ʻAuthenticationProvider`.

Les informations à acquérir doivent être une classe qui implémente ʻUserDetails`.

Une classe d'implémentation appelée JdbcDaoImpl est également fournie, mais comme les informations qui peuvent être obtenues sont limitées, je pense que je vais l'implémenter moi-même.

Processus d'authentification des appels

Fondamentalement, il est appelé par Filter. Par exemple, pour effectuer l'authentification par formulaire, ʻUsernamePasswordAuthenticationFilter est appelé. Ce filtre crée un objet ʻUsernamePasswordAuthenticationToken, qui est une classe d'implémentation de ʻAuthenticaion, à partir des informations d'entrée de l'utilisateur, et appelle le processus d'authentification de ʻAuthenticationManager. Si l'authentification réussit, la tâche consiste à définir les informations d'authentification acquises dans SecurityContextHolder. (Voir ci-dessous pour SecurityContextHolder)

Résumé du processus d'authentification à ce jour

ʻAuthenticationManagerest peu susceptible d'être implémenté. Il semble que vous devriez utiliser la classe d'implémentation par défautProviderManager. ʻAuthenticationProvider semble fournir la classe d'implémentation souhaitée, alors sélectionnez-la correctement. Cependant, si vous souhaitez créer une nouvelle méthode d'authentification telle que WebAuthn que Spring Security ne prend pas encore en charge, vous devrez l'implémenter. La même chose s'applique à Filter.

Vous créez souvent votre propre classe d'implémentation pour ʻUserDetailsService` pour obtenir des informations sur l'utilisateur.

Persistance des informations d'identification

En rendant persistantes les informations d'authentification obtenues après l'authentification terminée, il devient possible de déterminer si l'authentification a été effectuée ou non, et il est possible d'accéder aux informations de l'utilisateur.

永続化.png

SecurityContext

Un objet qui contient des informations d'identification (ʻAuthentication). Au lieu de conserver les informations d'identification telles quelles, persistez ce SecurityContext`.

SecurityContextRepository

Une interface pour rendre persistant SecurityContext. Vous pouvez penser à HttpSession comme un endroit pour conserver les informations d'identification, mais Spring Security fournit également HttpSessionSecurityContextRepository, qui est une classe d'implémentation qui utilise HttpSession. (Utilisez-le par défaut)

SecurityContextHolder

La classe qui contient le SecurityContext. Par défaut, il est conservé en utilisant ThreadLocal. Si vous souhaitez accéder à vos informations d'identification, vous pouvez les récupérer à partir de ce SecurityContextHolder au lieu d'accéder directement à HttpSession.

SecurityContextPersistenceFilter

Récupérez SecurityContext de SecurityContextRepository et définissez-le sur SecurityContextHolder avant le démarrage de tout processus. Une fois le traitement terminé, récupérez SecurityContext dans SecurityContextHolder, rendez-le persistant en utilisant SecurityContextRepository et supprimez SecurityContext de SecurityContextHolder. SecurityContextHolder utilise ThreadLocal, mais ce filtre gère le processus de suppression.

Résumé de la persistance

Les informations d'identification sont conservées en tant que SecurityContext, et SecurityContextRepository effectue le traitement lié à la persistance, mais vous n'avez pas besoin d'en être très conscient. Il est bon de se rappeler que vous pouvez obtenir le SecurityContext à partir du SecurityContextHolder.

Comportement après une authentification réussie ou non

Certains filtres qui appellent le processus d'authentification peuvent définir le comportement lorsque l'authentification réussit ou échoue. Par exemple, il peut être défini dans ʻUsernamePasswordAuthenticationFilterqui effectue l'authentification par formulaire, mais pas dansBasicAuthenticationFilter` qui effectue l'authentification de base.

AuthenticationSuccessHandler

認証成功.png

Définissez le processus lorsque l'authentification est réussie. Certaines classes d'implémentation sont fournies, mais «SavedRequestAwareAuthenticationSuccessHandler» est utilisé par défaut. Cette classe redirige une requête si elle est conservée dans RequestCache. S'il n'est pas conservé, redirigez vers l'ensemble d'URL par défaut.

Accédez à la page qui requiert une authentification dans l'état non authentifié et soyez redirigé vers l'écran d'authentification. Après cela, lorsque vous avez terminé l'authentification, vous pouvez passer à l'écran que vous tentiez d'afficher en premier car vous utilisez cette classe.

AuthenticationFailureHandler

認証失敗.png

Définissez le traitement en cas d'échec de l'authentification. Certaines classes d'implémentation sont également fournies, mais «SimpleUrlAuthenticationFailuerHandler» est utilisé par défaut. Cette classe est assez simple et redirige vers l'URL spécifiée. De plus, en stockant l'exception qui s'est produite lorsque l'authentification a échoué dans HttpSession, il est possible de s'y référer à la destination de la redirection.

Résumé des opérations après une authentification réussie et infructueuse

Utilisez ʻAuthenticationSuccessHandler et ʻAuthenticationFailuerHandler, respectivement, pour définir le comportement après une authentification réussie et infructueuse. La classe d'implémentation fournie ne redirige que vers l'URL spécifiée (en fonction des paramètres), donc si vous souhaitez effectuer des opérations avancées, vous devez créer une classe d'implémentation. Veuillez également noter qu'il peut ne pas être possible de définir en fonction de la méthode d'authentification.

Se déconnecter

Déconnectez-vous également. ログアウト.png

LogoutFilter

Après avoir appelé LogoutHandler qui effectue le traitement de déconnexion, appelezLogoutSuccessHandler qui effectue le post-traitement. Vous pouvez définir une URL pour vous déconnecter. (La valeur par défaut est / logout)

LogoutHandler

Déconnectez-vous du traitement. SecurityContextLogoutHandler rejette HttpSession. Ou est-ce une prémisse que les informations d'authentification sont stockées dans HttpSession? Je ne pense pas qu'il soit stocké dans HttpSession en fonction de l'implémentation de SecurityContextRepository. Mais il n'y a pas de méthode pour supprimer. Hum ...

Notez que LogoutFilter utilise une classe appelée CompositeLogoutHandler qui combine plusieurs LogoutHanlders, donc plusieursLogoutHandlers peuvent être exécutés en séquence selon les besoins.

LogoutSuccessHandler

Effectue le traitement une fois la déconnexion terminée. SimpleUrlLogoutSuccessHandler redirige vers l'URL spécifiée.

Résumé de la déconnexion

Si vous souhaitez personnaliser le processus de déconnexion, vous pouvez implémenter LogoutHandler et le définir sur LogoutFilter. Si vous souhaitez personnaliser la transition d'écran une fois la déconnexion terminée, implémentez LogoutSuccessHandler et définissez-le sur LogoutFilter.

URL de référence

à la fin

J'ai l'impression de comprendre Spring Security! (A cause de mon esprit)

Recommended Posts

Découvrez l'architecture de traitement de l'authentification Spring Security
À propos de l'authentification Spring Security
Authentification / autorisation de mémo d'utilisation de Spring Security
Mise en œuvre de la fonction d'authentification avec Spring Security ②
Implémentez la fonction d'authentification avec Spring Security ③
Tutoriel Spring Boot à l'aide de l'authentification Spring Security
Mise en œuvre de la fonction d'authentification avec Spring Security ①
Certification / autorisation avec Spring Security & Thymeleaf
Définissez le résultat de l'authentification Spring Security sur JSON
Authentification DB avec Spring Security et hachage avec BCrypt
Obtenez une authentification BASIC avec Spring Boot + Spring Security
Essayez l'authentification LDAP avec Spring Security (Spring Boot) + OpenLDAP
Ajoutez vos propres éléments d'authentification avec Spring Security
[Introduction à Spring Boot] Fonction d'authentification avec Spring Security
Exécutez un traitement arbitraire après l'authentification de base avec Spring Boot.
Spring Security soulève 403 interdits
Créer une authentification par clé API pour l'API Web dans Spring Security
Mémo d'utilisation de Spring Security CSRF
Mémo d'utilisation de Spring Security Run-As
Spring avec Kotorin --6 Traitement asynchrone
Spring Security Usage Memo Method Security
Mémo d'utilisation de Spring Security Remember-Me
Fonction de connexion avec Spring Security
[Spring Security] Spring Security sur GAE (SE)
Essayez d'utiliser Spring Boot Security
Mémo d'utilisation de Spring Security CORS
Test de mémo d'utilisation de Spring Security
Une erreur 404 se produit lors du test de l'authentification par formulaire avec Spring Security