origen
En RABC estándar, los permisos deben admitir la configuración dinámica, Spring Security es predeterminado para acordar los permisos en el código. Los escenarios comerciales reales generalmente requieren que los permisos de acceso a roles estén configurados dinámicamente, es decir, para configurar los roles de acceso correspondientes a las URL en tiempo de ejecución.
Según la seguridad de la primavera, ¿cómo lograr este requisito?
La forma más fácil es personalizar un filtro para completar el juicio de permiso, pero esto se separa del marco de seguridad de Spring. ¿Cómo implementarlo elegantemente según la seguridad de la primavera?
Revisión de autorización de seguridad de primavera
Spring Security FilterChainProxy se usa como un filtro para registrarse en la web. FilterChainProxy contiene múltiples filtros incorporados a la vez. Primero, necesitamos comprender los diversos filtros incorporados en la seguridad de la primavera:
| Alias | Clase de filtro | Elemento o atributo de espacio de nombres |
|---|---|---|
| Channel_filter | ChannelProcessingFilter | http/intercept-url@requiere canal |
| Security_Context_Filter | SecurityContextPersistenceFilter | http |
| Concurrent_session_filter | Concurrentesessionfilter | gestión de sesión/concurrencia control |
| Encabezados_filter | Encabezadowriterfilter | http/encabezados |
| Csrf_filter | Csrffilter | http/csrf |
| Logrout_filter | Suboutfilter | http/cierre de sesión |
| X509_filter | X509AuthenticationFilter | http/x509 |
| Pre_auth_filter | AbstractPreauthenticaticaticedProcessingFilter subclases | N / A |
| CAS_FILTER | CasauthenticationFilter | N / A |
| Form_login_filter | UserNamePassWordAuthenticationFilter | http/forma-login |
| Basic_auth_filter | BasicauthenticationFilter | http/http-basic |
| Servlet_api_support_filter | SecurityContextholderawarerequestFilter | http/@servlet-api-provisión |
| Jaas_api_support_filter | Jaasapiintegrationfilter | http/@jaas-api-provisión |
| Remember_me_filter | Recordarmeauthenticationfilter | http/recordar-yo |
| Anónimo_filter | Anonimonouthenticationfilter | http/anónimo |
| Session_management_filter | Filter de gestión de sesiones | gestión de la sesión |
| Excepcion_translation_filter | ExceptionTranslationFilter | http |
| Filter_security_interceptor | FiltersecurityInterceptor | http |
| Switch_user_filter | SwitchUserFilter | N / A |
Lo más importante es FilterSecurityInterceptor, que implementa la lógica de autenticación principal, y el código más central está aquí:
InterceptorStatUstoken protegido antes de la invocación (objeto objeto) {// Obtenga los permisos requeridos para acceder a la colección URL <EntabTribute> atributes = this.obtainsecurityMetadataSource () .getAttributes (objeto); Autenticación autenticada = autenticateiFrequired (); // Autenticación a través de AccessDecisionManager intente {this.accessDecisionManager.docide (autenticado, objeto, atributos); } Catch (AccessDeniedException AccessDeniedException) {PublisheVent (nuevo autorizationFailureEvent (objeto, atributos, autenticado, accessDeniedException)); Lanzar AccessDeniedException; } if (debug) {logger.debug ("autorización exitosa"); } if (PublishaUthorizationSuccessful ");} if (PublishaUthorizationsUccess) {PublisheVent (new AuthorizeSeVent (Object, Attributes, Authenticate);} // Intente ejecutar como una autenticación diferente de usuario = this.RunasManager.builildRunas (autenticado, Object, Object, Attributes); if (runas == NECHA == {logger.debug ("RunAsManager no cambió el objeto de autenticación"); SecurityContexTholder.getContext (); }Como se puede ver de lo anterior, para lograr la autenticación dinámica, podemos comenzar desde dos aspectos:
Veamos cómo implementarlo por separado.
AccessDecisionManager personalizado
Los tres mermos de acceso oficial se basan en AccessDecisionVoter para implementar la autenticación de permiso, por lo que solo necesitamos personalizar un AccessDecisionVoter.
La personalización implementa principalmente la interfaz AccessDecisionVoter. Podemos implementar un seguimiento de RoleVoter oficial:
Public Class BaseedVoTer implementa AccessDecisionVoter <ject> {@Override public Boolean Supports (configattribute attribute) {return true; } @Override public int vote (autenticación autenticación, objeto objeto, colección <ColegAttribute> atributos) {if (autenticación == null) {return access_denied; } int resultado = access_abstain; Colección <? extiende la Autoridad de GranTeDauthoridad = ExtractAuthorities (autenticación); for (configattribute attribute: attributes) {if (attribute.getAttribute () == null) {continuar; } if (this.supports (atributo)) {result = access_denied; // Intenta encontrar una autoridad otorgada de correspondencia para (otorDauthority Authority: Authorities) {if (attribute.getAttribute (). Equals (autory.getAuthority ())) {return access_granted; }}}} Resultado de retorno; } Colección <? extiende GrantedAuthority> ExtractAuthorities (autenticación de autenticación) {return Authentication.getAuthorities (); } @Override public Boolean Supports (Class Clazz) {return true; }}¿Cómo agregar permisos dinámicos?
El tipo de objeto de objeto en vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) es filtreInVocation, y puede obtener la URL de la solicitud actual a través de GetRequesturl:
FilterInVocation fi = (filtreInVocation) objeto; Cadena url = fi.getRequesturl ();
Por lo tanto, hay mucho espacio para la expansión aquí. Puede cargarlo dinámicamente desde el DB y luego juzgar el Configuración de la URL.
¿Cómo usar este rol BasedVoter? Use el método AccessDecisionManager para personalizar en la configuración. Deberíamos usar el oficial unánime oficial y luego agregar el rol de rol personalizado.
@Enablewebsecurity @enableglobalmethodsecurity (prepostenAnted = true, secuedEnabled = true) public class SecurityConfiguration extiende WebSecurityConfigurerAdapter {@Override Protected Void Configuración (HttpSecurity Http) arroja excepción {http .addfilterbebeFore (Corsfilter,,,,,, corsfilter,,,,, Corsfilter,,, Corsfilter,. UserNamePassWalDauthenticationFilter.Class) .ExceptionHandling () .AuthenticationEntryPoint (ProblemsUpport) .AccessDeniedHandler (Problemsupport) .and () .csrf () .disable () .headers (). .SessionCreationPolicy (SessionCreationPolicy.stateless) .And () .Authorizequests () // AccessDecisionManager .accessDecisionManager (AccessDecisionManager ()) .And () .Apply (SecurityConfigurerAdapter ()); } @Bean Public AccessDecisionManager AccessDecisionManager () {list <AccessDecisionVoter <? extiende objeto >> decisionVoters = arrays.aslist (new WebExPressionVoter (), // new RoleVoter (), New RoleBasedVoter (), new AuthenticateVoter ()); devolver nuevo unanimoso (DecisionVoters); }Personalizar SecurityMetadataSource
FilterInvocationsEcationSecurityMetAdataSource personalizado solo necesita implementar la interfaz y cargar dinámicamente las reglas de DB en la interfaz.
Para reutilizar las definiciones en el código, podemos tomar el SecurityMetadataSource generado en el código y pasar en el FilterInvocationsecurityMetAdataSource predeterminado en el constructor.
Public Class AppFilterInvocationsecurityMetAdataSource implementa org.springframework.security.web.access.intercept.filterInvocationsecurityMetAdataSource {PRIVAD FILTERINVOCATIONSECURITYMEDATATATASOURTATASOURCE; @Override Public Collection <EnfigAttribute> getAllConfigAttributes () {return null; } Public AppFilterInvocationsecurityMetAdataSource (FilterInVocationsecurityMetAdataSource ExpressionBasedFilterInvocationSecurityMetAdataSource) {this.suPermetAdataSource = ExpressionBasedFilterInVocationAdationMetAdataSource; // Configuración de permiso de carga de la base de datos} AntpathMatcher Final Private AntPathMatcher = new AntPathMatcher (); // Aquí necesita cargar mapa final privado <string, string> urlroleMap = new Hashmap <String, String> () {{Put ("/Open/**", "role_anonymous"); put ("/salud", "rol_anonymous"); put ("/reiniciar", "role_admin"); put ("/demo", "role_user"); }}; @Override Public Collection <EnfigAttribute> getAttributes (objeto objeto) arroja ilegalArgumentException {filterInVocation fi = (filtreInVocation) objeto; Cadena url = fi.getRequesturl (); for (map.entry <string, string> Entry: urlroleMap.Entryset ()) {if (antpathMatcher.match (entry.getKey (), url)) {return SecurityConfig.CreateList (Entry.getValue ()); }} // Devuelve la configuración predeterminada definida por el código return supermetadataSource.getAttributes (objeto); } @Override public Boolean Supports (class <?> Clazz) {return filtinVocation.class.isassignableFrom (Clazz); }}¿Cómo usarlo? A diferencia de AccessDecisionManager, ExpressionUrlauthorizationConfigurer no proporciona un método establecido para establecer FilterInVocationSecurityMetAdataSource de FiltersecurityInterceptor, ¿cómo hacerlo?
Descubra un método de extensión con OBJECTPOSTProcessor, a través del cual personaliza un ObjectPostProcessor que maneja el Tipo de Interceptor de FiltersCurity, puede modificar FilterSecurityInterceptor.
@Enablewebsecurity @enableglobalmethodsecurity (prepostenAnted = true, secuedEnabled = true) public class SecurityConfiguration extiende WebSecurityConfigurerAdapter {@Override Protected Void Configuración (HttpSecurity Http) arroja excepción {http .addfilterbebeFore (Corsfilter,,,,,, corsfilter,,,,, Corsfilter,,, Corsfilter,. UserNamePassWalDauthenticationFilter.Class) .ExceptionHandling () .AuthenticationEntryPoint (ProblemsUpport) .AccessDeniedHandler (Problemsupport) .and () .csrf () .disable () .headers (). .SessionCreationPolicy (sessionCreationPolicy.stateless) .And () .AuthorizeRequests () // FilterInvocationsCurityMetadataSource .withObjectPostPosTposSprocessor (nuevo ObjectPoScessor <FilterSecurityInterceptore> () {@Override public <o ExtendsCendsinterceptor> o fsio FSI.SetSecurityMetAdataSource (mySecurityMetAdataSource (fsi.getSecurityMetAdataSource ())); } @Bean Public AppFilterInVocationsCurityMetAdataSource mySecurityMetAdataSource (filtreInVocationsecurityMetAdataSource FilterInVocationsecurityMetAdataSource) AppFilterInvocationsecurityMetAdataSource (FilterInvocationsecurityMetadataSource); return SecurityMetadataSource;}resumen
Este artículo presenta dos métodos para implementar permisos dinámicos basados en la seguridad de la primavera. Una es personalizar el AccessDecisionManager, y el otro es personalizar el FilterInVocationSecurityMetAdataSource. Puede elegir de manera flexible de acuerdo con sus necesidades en proyectos reales.
Lectura adicional:
Arquitectura de seguridad de primavera y análisis del código fuente
Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.