tutorial j_spring_security_check example español ejemplo spring-security authorization security-roles

j_spring_security_check - ¿Cómo decidir dinámicamente el valor del atributo de acceso<intercept-url> en Spring Security?



spring security tutorial español pdf (6)

Así es como se puede hacer en Spring Security 3.2:

@Configuration @EnableWebMvcSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public SecurityConfigDao securityConfigDao() { SecurityConfigDaoImpl impl = new SecurityConfigDaoImpl() ; return impl ; } @Override protected void configure(HttpSecurity http) throws Exception { /* get a map of patterns and authorities */ Map<String,String> viewPermissions = securityConfigDao().viewPermissions() ; ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry interceptUrlRegistry = http .authorizeRequests().antMatchers("/publicAccess/**") .permitAll(); for (Map.Entry<String, String> entry: viewPermissions.entrySet()) { interceptUrlRegistry.antMatchers(entry.getKey()).hasAuthority(entry.getValue()); } interceptUrlRegistry.anyRequest().authenticated() .and() ... /* rest of the configuration */ } }

En Spring Security utilizamos la etiqueta intercept-url para definir el acceso para las URL de la siguiente manera:

<intercept-url pattern="/**" access="ROLE_ADMIN" /> <intercept-url pattern="/student" access="ROLE_STUDENT" />

Esto está codificado en applicationContext-security.xml . En su lugar, quiero leer los valores de acceso de una tabla de base de datos. UserDetailsService mi propio UserDetailsService y leí las funciones para el usuario que UserDetailsService sesión en la base de datos. ¿Cómo asigno estos roles a los patrones de URL durante el tiempo de ejecución?


En realidad, spring security 3.2 no recomienda hacer esto de acuerdo con http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/faq.html#faq-dynamic-url-metadata

pero, es posible (pero no elegante) usar el elemento http en el espacio de nombres con un accessDecisionManager personalizado.

La configuración debe ser:

<http pattern="/login.action" security="none"/> <http pattern="/media/**" security="none"/> <http access-decision-manager-ref="accessDecisionManager" > <intercept-url pattern="/**" access="ROLE_USER"/> <form-login login-page="/login.action" authentication-failure-url="/login?error=1" default-target-url="/console.action"/> <logout invalidate-session="true" delete-cookies="JSESIONID"/> <session-management session-fixation-protection="migrateSession"> <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/login.action"/> </session-management> <!-- NO ESTA FUNCIONANDO, los tokens no se ponen en el request! <csrf /> --> </http> <authentication-manager> <authentication-provider> <user-service> <user name="test" password="test" authorities="ROLE_USER" /> </user-service> </authentication-provider> </authentication-manager> <beans:bean id="accessDecisionManager" class="openjsoft.core.services.security.auth.CustomAccessDecisionManager"> <beans:property name="allowIfAllAbstainDecisions" value="false"/> <beans:property name="decisionVoters"> <beans:list> <beans:bean class="org.springframework.security.access.vote.RoleVoter"/> </beans:list> </beans:property> </beans:bean>

CustomAccessDecisionManager debería ser ...

public class CustomAccessDecisionManager extends AbstractAccessDecisionManager { ... public void decide(Authentication authentication, Object filter, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if ((filter == null) || !this.supports(filter.getClass())) { throw new IllegalArgumentException("Object must be a FilterInvocation"); } String url = ((FilterInvocation) filter).getRequestUrl(); String contexto = ((FilterInvocation) filter).getRequest().getContextPath(); Collection<ConfigAttribute> roles = service.getConfigAttributesFromSecuredUris(contexto, url); int deny = 0; for (AccessDecisionVoter voter : getDecisionVoters()) { int result = voter.vote(authentication, filter, roles); if (logger.isDebugEnabled()) { logger.debug("Voter: " + voter + ", returned: " + result); } switch (result) { case AccessDecisionVoter.ACCESS_GRANTED: return; case AccessDecisionVoter.ACCESS_DENIED: deny++; break; default: break; } } if (deny > 0) { throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied")); } // To get this far, every AccessDecisionVoter abstained checkAllowIfAllAbstainDecisions(); } ... }

Donde getConfigAttributesFromSecuredUris recupera las funciones de formulario DB de la URL específica


Esta es la solución que he aplicado para dividir la lista de entradas de URL de intercepción de la otra configuración de seguridad de primavera.

<security:custom-filter ref="parancoeFilterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" /> ........ <bean id="parancoeFilterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor" > <property name="authenticationManager" ref="authenticationManager"/> <property name="accessDecisionManager" ref="accessDecisionManager"/> <property name="securityMetadataSource" ref="securityMetadataSource"/> </bean>

Bean securityMetadataSource se puede colocar en el mismo archivo de configuración o en otro archivo de configuración.

<security:filter-security-metadata-source id="securityMetadataSource" use-expressions="true"> <security:intercept-url pattern="/admin/**" access="hasRole(''ROLE_ADMIN'')" /> </security:filter-security-metadata-source>

Por supuesto, puede decidir implementar su propio bean securityMetadataSource implementando la interfaz FilterInvocationSecurityMetadataSource. Algo como esto:

<bean id="securityMetadataSource" class="mypackage.MyImplementationOfFilterInvocationSecurityMetadataSource" />

Espero que esto ayude.


La clase FilterInvocationSecurityMetadataSourceParser en Spring-security (intente Ctrl / Cmd + Shift + T en STS con el código fuente) analiza las etiquetas intercept-url y crea instancias de ExpressionBasedFilterInvocationSecurityMetadataSource, que extiende DefaultFilterInvocationSecurityMetadataSource que implementa FilterInvocationSecurityMetadataSource que amplía SecurityMetadataSource.

Lo que hice fue crear una clase personalizada que implemente FilterInvocationSecurityMetadataSource , OptionsFromDataBaseFilterInvocationSecurityMetadataSource . Usé DefaultFilterInvocationSecurityMetadataSource como base para usar urlMatcher, para implementar el método support () y algo así.

Entonces debes implementar estos métodos:

  • Colección getAttributes (Objeto Object), donde se puede acceder a la base de datos, buscando el ''objeto'' que se está asegurando (normalmente la URL a la que acceder) para obtener los atributos permitidos de ConfigAttribute (normalmente los ROLE)

  • soportes booleanos (Class clazz)

  • Colección getAllConfigAttributes ()

Tenga cuidado con el último, porque se llama al inicio y tal vez no está bien configurado en este momento (es decir, con los orígenes de datos o el contexto de persistencia conectados automáticamente, según lo que esté usando). La solución en un entorno web es configurar el contextConfigLocation en el web.xml para cargar el applicationContext.xml antes de la aplicaciónContext-security.xml

El último paso es personalizar la aplicaciónContext-security.xml para cargar este bean.

Para hacer eso, usé beans regulares en este archivo en lugar del espacio de nombres de seguridad:

<beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy"> <filter-chain-map path-type="ant"> <filter-chain pattern="/images/*" filters="none" /> <filter-chain pattern="/resources/**" filters="none" /> <filter-chain pattern="/**" filters=" securityContextPersistenceFilter, logoutFilter, basicAuthenticationFilter, exceptionTranslationFilter, filterSecurityInterceptor" /> </filter-chain-map> </beans:bean>

Debes definir todos los beans relacionados. Por ejemplo:

<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <beans:property name="authenticationManager" ref="authenticationManager"></beans:property> <beans:property name="accessDecisionManager" ref="affirmativeBased"></beans:property> <beans:property name="securityMetadataSource" ref="optionsFromDataBaseFilterInvocationSecurityMetadataSource"></beans:property> <beans:property name="validateConfigAttributes" value="true"/></beans:bean>

Sé que no es una respuesta bien explicada, pero no es tan difícil como parece.

Simplemente use la fuente de resorte como base y obtendrá lo que quiera.

La depuración con los datos en su base de datos, le ayudará mucho.


Tengo casi el mismo problema, básicamente me gustaría mantener separada la lista de URL de intercepción de la otra sección de configuración de seguridad de primavera, la primera en pertenecer a la configuración de la aplicación, la última a la configuración del producto (núcleo, complemento).

Hay una proposal en la JIRA de primavera, sobre este problema.

No quiero renunciar al uso del espacio de nombres de seguridad de primavera, así que estaba pensando en algunas soluciones posibles para enfrentar esto.

Para tener la lista de URL de intercepción creada dinámicamente, debe inyectar el objeto securitymetadatasource en FilterSecurityInterceptor. Con el esquema springsecurity, la clase HttpBuilder crea la instancia de FilterSecurityInterceptor y no hay forma de pasar el securitymetadatasource como propiedad definida en el archivo de configuración del esquema, y ​​menos el tipo de solución alternativa, que podría ser:

  • Defina un filtro personalizado, que se ejecutará antes de FilterSecurityInterceptor, en este filtro recuperando la instancia FilterSecurityInterceptor (suponiendo que se define una sección http única) por el contexto de primavera e inyecte allí la instancia securitymetadatasource;
  • Lo mismo que arriba, pero en HandlerInterceptor.

¿Qué piensas?


Una solución simple que funciona para mí.

<intercept-url pattern="/**/**" access="#{@customAuthenticationProvider.returnStringMethod}" /> <intercept-url pattern="/**" access="#{@customAuthenticationProvider.returnStringMethod}" />

customAuthenticationProvider es un bean

<beans:bean id="customAuthenticationProvider" class="package.security.CustomAuthenticationProvider" />

en el método de creación de clase CustomAuthenticationProvider:

public synchronized String getReturnStringMethod() { //get data from database (call your method) if(condition){ return "IS_AUTHENTICATED_ANONYMOUSLY"; } return "ROLE_ADMIN,ROLE_USER"; }