origine
Dans RABC standard, les autorisations doivent prendre en charge la configuration dynamique, Spring Security par défaut s'accorde sur les autorisations dans le code. Les scénarios commerciaux réels nécessitent généralement que les autorisations d'accès aux rôles soient configurées dynamiquement, c'est-à-dire pour configurer les rôles d'accès correspondant aux URL lors de l'exécution.
Sur la base de la sécurité du printemps, comment réaliser cette exigence?
Le moyen le plus simple consiste à personnaliser un filtre pour compléter le jugement de l'autorisation, mais cela est séparé du cadre de sécurité de Spring. Comment le mettre en œuvre élégamment en fonction de la sécurité du printemps?
Revue d'autorisation de sécurité du printemps
Spring Security FilterChainProxy est utilisé comme filtre pour s'inscrire avec le Web. FilterChainProxy contient plusieurs filtres intégrés à la fois. Tout d'abord, nous devons comprendre les différents filtres intégrés dans la sécurité du printemps:
| Alias | Classe de filtre | Élément ou attribut de l'espace de noms |
|---|---|---|
| Canal_filter | ChannelProcessingFilter | http / intercept-url @ nécessaire-channel |
| Sécurité_context_filter | SecurityContextPersistenceFilter | http |
| Concurrent_session_filter | ConcurrentSessionfilter | Session-Management / Concurrence Control |
| En-têtes_filter | Headwriterfilter | http / en-têtes |
| Csrf_filter | Csrffilter | http / csrf |
| Logout_filter | Déconnexion | http / déconnexion |
| X509_filter | X509 AuthenticationFilter | http / x509 |
| Pre_auth_filter | AbstractPreAuthenticatedProcessingFilter Sousses | N / A |
| Cas_filter | Casauthenticationfilter | N / A |
| Form_login_filter | UserNamepasswordAuthenticationFilter | HTTP / Form-Login |
| Basic_auth_filter | Basic AuthenticationFilter | http / http-basic |
| Servlet_api_support_filter | SecurityContextholderawareRequestFilter | http / @ servlet-api-provision |
| Jaas_api_support_filter | Jaasapiintegrationfilter | http / @ jaas-api-provision |
| Rappeler_me_filter | RememberMeauthenticationFilter | HTTP / REVOEZ-ME |
| Anonymous_filter | AnonymousAuthenticationFilter | HTTP / Anonyme |
| Session_management_filter | SessionManagementFilter | gestion de session |
| Exception_translation_filter | ExceptionTranslationfilter | http |
| Filter_security_interceptor | FiltreSecurity Interceptor | http |
| Switch_user_filter | Switchuserfilter | N / A |
La chose la plus importante est FiltersecurityInterceptor, qui implémente la principale logique d'authentification, et le code le plus principal est ici:
Protégé interceptorStatUstAnkEnked avantInvocation (objet objet) {// Obtenez les autorisations requises pour accéder aux attributs de collection URL <ImgAttribute> = this.obtainSecurityMetAdataSource () .GetAttributes (objet); Authentification authentifiée = authenticadiaFrequired (); // Authentification via AccessDecisionManager try {this.accessdecisionmanager.docide (authentifié, objet, attributs); } catch (AccessEniedException AccessEniedException) {PublisheVent (nouvelle autorisationFaiLureEvent (objet, attributs, authentifié, AccessEnedException)); lancer AccessEniedException; } if (debug) {logger.debug ("Autorisation réussie"); } if (publihAuthorizationsUCcessful ");} if (publihAuthorizationsUCcess) {publiseVent (new AuthorizedEvent (objet, attributs, Authenticated));} // tenter d'exécuter comme un autre utilisateur Runas = this.Runasmanager. (Debug) {Logger.Debug (RunasManager n'a pas modifié l'objet d'authentification ");} // = SecurityContexTholder.getConted ();Comme on peut le voir à partir de ce qui précède, pour obtenir une authentification dynamique, nous pouvons commencer à partir de deux aspects:
Voyons comment l'implémenter séparément.
Custom AccessDecisionManager
Les trois ACCESSECISIONMANGERS OFFICIELS sont tous basés sur AccessDecisionVoter pour implémenter l'authentification de l'autorisation, nous n'avons donc qu'à personnaliser un AccessDecisionVoter.
La personnalisation implémente principalement l'interface AccessDecisionVoter. Nous pouvons mettre en œuvre un suivant suivant le voleur officiel:
La classe publique RôleBasedVoter implémente AccessDecisionVoter <objet> {@Override public booléan supports (configAttribute attribut) {return true; } @Override public int vote (authentification Authentication, objet objet, collection <Icongattribute> Attributs) {if (authentication == null) {return Access_denied; } int result = access_abstain; Collection <? étend l'autorité accorde> autorités = extratauthorités (authentification); for (configAttribute attribut: attributes) {if (attribut.getAttribute () == null) {continu; } if (this.Supports (attribut)) {result = access_denedy; // tenter de trouver une autorité accordée à (AccordedAuthority Authority: Authorities) {if (attribut.getAttribute (). Equals (Authority.getAuthority ())) {return Access_Granted; }}}} Retour Résultat; } Collection <? étend l'autoritaire accordé> ExtractAuthorities (authentification authentification) {return authentication.getAuthorities (); } @Override public booléen supports (class Clazz) {return true; }}Comment ajouter des autorisations dynamiques?
Le type d'objet d'objet dans vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) est la filtration de la révocation, et vous pouvez obtenir l'URL de la demande actuelle via GetRequesTurl:
FilteRinvocation fi = (filterInvocation) objet; String url = fi.getRequestUrl ();
Par conséquent, il y a beaucoup de place pour l'expansion ici. Vous pouvez le charger dynamiquement à partir de la base de données, puis juger le configattribut de l'URL.
Comment utiliser ce rolebasedVoter? Utilisez la méthode AccessDecisionManager pour personnaliser en configuration. Nous devons utiliser la base unanime officielle, puis ajouter le voleur de rôle personnalisé.
@ Activerwebsecurity @ enableglobalMethodSecurity (prestenabled = true, sécuréable = true) classe publique SecurityConfiguration étend WebSecurityConfigurerAdapter {@Override Protected Void Configure (httpSecurity http) lance l'exception {http .AddFilterBeFore (Corsfilter, UsernamEpasswordFilterFilterBefore) .ExceptionHandling () .AuthenticationEntryPoint (Problemsupport) .AccessdeniedHandler (ProblemSupport) .And () .Csrf () .Disable () .heders () .FrameOptions () .Disable () .and () .SessionManagement () .SessionCreationPolicy (sessionCreationPolicy. // Custom AccessDecisionManager .AccessSidecisionManager (AccessDecisionManager ()) .And () .Apply (SecurityConfigurerAdapter ()); } @Bean public AccessDecisionManager AccessDecisionManager () {list <AccessDecisionVoter <? étend objet >> DecisionVoters = arrays.aslist (new WebExpressionVoter (), // new RoleVoter (), new RoleBasedVoter (), new AuthenticatedVoter ()); retourner de nouvelles basées unanime (DecisionVoters); }Personnaliser SecurityMetAdatasource
FilteRINVocationSecurityMetAdataSource personnalisé n'a besoin que d'implémenter l'interface et de charger dynamiquement les règles de DB dans l'interface.
Afin de réutiliser les définitions dans le code, nous pouvons prendre la sécurité de sécurité générée dans le code et passer dans le FilteRinvocationSecurityMetAdataSource par défaut dans le constructeur.
classe publique AppFilteRinvocationSecurityMetAdataSource implémente org.springframework.security.web.access.intercept.filteRinvocationSecurityMetAdatasource {private filteRinvocationsecurityMetadatasource supermetadatasource; @Override public Collection <IcongAnTTribute> getAllConfigAttributes () {return null; } public AppFilteRinvocationSecurityMetAdataSource (FilteRinvocationSecurityMetAdataSource expressionBasedFilteRinvocationSecurityMetAdataSource) {this.supermetadatasource = expressionbasedFilteRinvocationSucureMetAdatasource; // Configuration de l'autorisation de chargement TODO à partir de la base de données} private final antpathmatcher antpathmatcher = new antpathmatcher (); // Ici, vous devez charger la carte finale privée <chaîne, string> urlROlemap = new HashMap <String, String> () {{put ("/ open / **", "Role_anonymous"); put ("/ health", "role_anonymous"); put ("/ redémarrer", "role_admin"); put ("/ démo", "role_user"); }}; @Override public Collection <ImgAttribute> GetAttributes (objet objet) lève illégalArgumentException {filterInvocation fi = (filteRinvocation) objet; String url = fi.getRequestUrl (); pour (map.entry <string, string> entrée: urlrolemap.entryset ()) {if (antpathmatcher.match (entry.getKey (), url)) {return securityConfig.createElist (entry.getValue ()); }} // renvoie la configuration par défaut définie par le code return superMetAdataSource.getAttributes (objet); } @Override public Boolean Supports (classe <?> Clazz) {return filteRinvocation.class.issignableFrom (Clazz); }}Comment l'utiliser? Contrairement à AccessDecisionManager, ExpressionUrlAuthorizationConfigurer ne fournit pas de méthode définie pour définir le filteRinvocationSecurityMetAdataSource de FilterSecurityInterceptor, comment faire?
Découvrez une méthode d'extension WithObjectPostProcessor, à travers laquelle personnalise un objetPostProcessor qui gère le type FilterSecurityInterceptor, vous pouvez modifier FilterSecurityInterceptor.
@ Activerwebsecurity @ enableglobalMethodSecurity (prestenabled = true, sécuréable = true) classe publique SecurityConfiguration étend WebSecurityConfigurerAdapter {@Override Protected Void Configure (httpSecurity http) lance l'exception {http .AddFilterBeFore (Corsfilter, UsernamEpasswordFilterFilterBefore) .ExceptionHandling () .AuthenticationEntryPoint (Problemsupport) .AccessdeniedHandler (ProblemSupport) .And () .Csrf () .Disable () .heders () .FrameOptions () .Disable () .and () .SessionManagement () .SessionCreationPolicy (sessionCreationPolicy. // FilteRinVocationSecurityMetAdataSource personnalisé .WithObjectPostProcessor (New ObjectPostProcessor <FilterSecurityInterceptor> () {@Override public <o étend FilterSecurityInterceptor> o PostProcess (o fsi) { FSI.SetSecurityMetAdataSource (MySeCurityMetAdataSource (fsi.getSecurityMetAdataSource ())); } @Bean public AppFilteRinvocationSecurityMetAdataSource mySecurityMetAdataSource (FilteRinvocationSecurityMetAdatasource FilteRinvocationSecurityMetAdatasource) {AppFilteRinvocationSecurityMetAdataSource SecurityMetAdatasource = New AppFilteRinvocationSecurityMetAdataSource (FilteRinvocationSecurityMetAdataSource); Retour SecurityMetAdataSource;}résumé
Cet article présente deux méthodes pour implémenter les autorisations dynamiques basées sur la sécurité du printemps. L'un consiste à personnaliser le AccessDecisionManager, et l'autre est de personnaliser le filteRinvocationsecurityMetAdataSource. Vous pouvez choisir de manière flexible en fonction de vos besoins dans les projets réels.
Lire plus approfondie:
Architecture de sécurité printanière et analyse de code source
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.