securitycontextholder security spring ioc-container servlets security-context

securitycontextholder - Declaración de Spring Bean en el contexto de los padres frente al contexto de los niños



ioc-container servlets (1)

Tengo un objeto bean de primavera (dao) que instancia en mi ServletContext a través del siguiente xml:

<bean id="userDao" class="com.company.dao.impl.UserDaoImpl"> <property name="sessionFactory" ref="sessionFactory" /> </bean>

Este bean se declara dentro de mi archivo webapp-servlet.xml y lo utiliza mi aplicación dentro de ServletContext.

También estoy usando SpringSecurity. Tengo entendido que esto se ejecuta en un contexto diferente (el SecurityContext).

Mi aplicación tiene un webapp-security.xml donde instalo un proveedor de autenticación personalizado. Me gustaría usar mi dao que se usa en mi aplicación para hacer también la búsqueda de usuarios en mi contexto de seguridad, pero cuando ejecuto:

<bean id="userAuthenticationProvider" class="com.company.security.UserAuthenticationProvider"> <property name="userDao" ref="userDao" /> </bean>

Recibo errores que dicen que no hay tal bean "userDao". El bean se autoconecta bien en beans declarados en mi otro contexto, pero no dentro de mi contexto de seguridad. Según Spring Docs, creo que ambos contextos separados son necesarios en web.xml

<listener> <listener-class>org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <listener> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher </listener-class> </listener>

Entonces mi pregunta es, ¿cómo puedo obtener acceso a mi DAO que vive en mi ServletContext dentro de mi SecurityContext? ¿Hay un modificador de alcance para mi dao, o podría de alguna manera obtener el ServletContext en tiempo de ejecución dentro de mi proveedor de autenticación? Como referencia, así es como quiero usarlo dentro de mi proveedor de autenticación:

public class UserAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @Override protected UserDetails retrieveUser(String userName, UsernamePasswordAuthenticationToken authenticationToken) throws AuthenticationException { // use dao here

gracias por explicarme esto

ACTUALIZAR:

Continuando con mi investigación, parece que DispatcherServlet, donde estoy usando mi daos, es un contexto secundario, y el contexto de seguridad está en algún lugar más arriba. En consecuencia, los beans en mi DispatcherServlet no se pueden ver por contextos principales. Creo que la respuesta es mover mis declaraciones de frijol en el contexto de la aplicación principal de alguna manera, pero no estoy seguro de cómo hacer esto. Aquí está mi web.xml

<context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/spring-*.xml </param-value> </context-param> <listener> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher </listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>myapp</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>listings</param-name> <param-value>true</param-value> </init-param> </servlet> ...

Moví toda mi creación de dao a un archivo spring-dao.xml, y en spring-security.xml ahora estoy haciendo un:

<import resource="spring-dao.xml" />

Los daos stil permanecen visibles para el contexto de DispatcherServlet e invisibles para mi SecurityContext.

CONTESTADA:

De acuerdo, lo descubrí. Aquí hay algunos enlaces útiles:

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#context-create

http://forum.springsource.org/showthread.php?115774-Spring-Security-Custom-UserDetailsService-to-use-User-Service-Dao

http://static.springsource.org/spring-security/site/faq.html#faq-method-security-in-web-context

Entonces, el problema era que necesitamos asegurarnos de que el dao existe en ApplicationContext (contenedor de primavera más alto). Para asegurarme de que esto sucediera, cambié mi web.xml para que fuera:

<context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/spring-dao.xml WEB-INF/spring-security.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <listener> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher </listener-class> </listener> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>webapp</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>listings</param-name> <param-value>true</param-value> </init-param> </servlet>

Pensé que esto me aseguraría que el primer cargador de contexto que se iniciara leería mi configuración dao (y crearía mis beans Dao), luego mi configuración de seguridad. Como los beans Dao se están creando de esta manera, eliminé la sentencia anterior "import resource =" spring-dao.xml "" en security.xml porque ya no será necesaria.

Justo después de esa configuración context-param, creé el ContextLoaderListener. Este es un contenedor de primavera de mayor nivel que DispatcherServlet, así que pensé que ponerlo primero sería el primero en leer los archivos de configuración, y luego crearía los beans. Entonces, cualquier contexto infantil tendría acceso a ellos. Puede que no sea así como funciona, ya que DispatcherServlet ni siquiera puede leer el contextConfigLocation, pero incluso si lo hace, pensé que en este punto los beans ya estarían declarados, por lo que es malo, el contexto principal los posee.

Ahora, para otro truco ... para obtener mi DAO, no pude @Autowired. Tuve que inyectarlo manualmente a través de XML:

<bean id="userAuthenticationProvider" class="com.company.app.security.UserAuthenticationProvider"> <property name="userDao" ref="userDao" /> </bean>

Por supuesto, hice los métodos getter y setter en mi dao, ¡y listo! No sé por qué el @Autowired no funciona aquí. Supongo que es por diseño. Tal vez esto es particular para el SecurityContext (no se extraerá de otros contextos), o tal vez @Autowired en general solo se extrae del contexto actual, o tal vez porque he creado el bean a través de XML, también tengo que establecer las propiedades a través de XML y no a través de anotaciones? (las anotaciones están habilitadas y funcionan en mi espacio de nombres de aplicaciones de nivel superior).

De todos modos ... todavía no entiendo mucho, pero el punto importante es que finalmente está funcionando.


Si va a utilizar Spring MVC, definitivamente necesita comprender la jerarquía ApplicationContext de Spring MVC . También debe aprender algo sobre los componentes básicos y los ciclos de vida en un contenedor de servlets , ya que parece estar confundido acerca de cómo funcionan los oyentes y servlets.

Para explicar tu situación brevemente:

  1. Está creando dos ApplicationContexts: el contexto raíz y el contexto DispatcherServlet. El contexto raíz es creado por ContextLoaderListener en base a los archivos nombrados en contextConfigLocation. Este contexto está destinado a contener los beans que componen la lógica central de su aplicación. El contexto DispatcherServlet se crea cuando ese servlet se inicia y se basa en el archivo llamado "webapp-servlet.xml". Este contexto está destinado a contener cualquier frijol que admita la instancia DispatcherServlet con la que está asociado y solo debería contener frijoles relacionados con la vista.
  2. El contexto DispatcherServlet se convierte en un elemento secundario del contexto raíz. Eso permite inyectar sus beans centrales desde el contexto raíz en los beans de la capa de vista. La visibilidad es unidireccional. Los beans de la capa de visualización no están disponibles para los beans del núcleo, lo cual es deseable. Esta es la razón por la que su DAO no pudo ser inyectado en su proveedor de autenticación. El DAO estaba en el contexto del niño.
  3. Los servicios basados ​​en anotaciones solo se aplican dentro del contexto donde se declaran. Si @Autowired no está funcionando para un bean en particular, es porque no ha declarado <context:component-scan/> o <context:annotation-config/> en el contexto donde existe ese bean.