gpt4 book ai didi

security - 在父上下文与子上下文中声明 Spring Bean

转载 作者:IT老高 更新时间:2023-10-28 13:47:20 25 4
gpt4 key购买 nike

我有一个 spring bean (dao) 对象,我通过以下 xml 在我的 ServletContext 中实例化它:

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

这个 bean 在我的 webapp-servlet.xml 文件中声明,并被我的应用程序在 ServletContext 中使用。

我也在使用 SpringSecurity。我的理解是它在不同的上下文(SecurityContext)中运行。

我的应用程序有一个 webapp-security.xml,我在其中实例化了一个自定义身份验证提供程序。我想使用我的应用程序中使用的 dao 来在我的安全上下文中进行用户查找,但是当我运行时:
<bean id="userAuthenticationProvider" class="com.company.security.UserAuthenticationProvider">
<property name="userDao" ref="userDao" />
</bean>

我收到错误消息,说没有这样的 bean“userDao”。 bean 在我的其他上下文中声明的 bean 中 Autowiring 得很好,但不在我的安全上下文中。根据 Spring Docs,我相信 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>

所以我的问题是,我如何才能访问位于我的 SecurityContext 内的 ServletContext 中的 DAO?我的 dao 是否有范围修饰符,或者我可以在运行时以某种方式在身份验证提供程序中获取 ServletContext 吗?作为引用,这是我想在身份验证提供程序中使用它的方式:
public class UserAuthenticationProvider extends
AbstractUserDetailsAuthenticationProvider {

@Override
protected UserDetails retrieveUser(String userName,
UsernamePasswordAuthenticationToken authenticationToken)
throws AuthenticationException {

// use dao here

谢谢你向我解释这个

更新:

继续我的调查,似乎我使用 daos 的 DispatcherServlet 是一个子上下文,而安全上下文位于更高的位置。因此,父上下文无法看到我的 DispatcherServlet 中的 bean。我认为答案是以某种方式将我的 bean 声明移动到父应用程序上下文中,但我不确定如何执行此操作。这是我的 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>

...

我将所有 dao 创建移到 spring-dao.xml 中,在 spring-security.xml 中,我现在正在执行以下操作:
<import resource="spring-dao.xml" />

daos 仍然对 DispatcherServlet 上下文可见,但对我的 SecurityContext 不可见。

回答:

好吧,我想通了。以下是一些有用的链接:

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

所以问题是我们需要确保 dao 存在于 ApplicationContext(更高层的 spring 容器)中。为了确保发生这种情况,我将 web.xml 更改为:
<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>

我认为这将确保启动的第一个上下文加载器将读取我的 dao 配置(并创建我的 dao bean),然后是我的安全配置。由于 dao bean 是以这种方式创建的,因此我删除了 security.xml 中先前的“import resource="spring-dao.xml"”语句,因为它将不再需要。

在上下文参数配置之后,我创建了 ContextLoaderListener。这是一个比 DispatcherServlet 更高级别的 spring 容器,所以我认为把它放在最前面会是第一个读取这些配置文件的人,然后他会创建 bean。然后,任何子上下文都可以访问它们。这可能不是它的工作方式,因为 DispatcherServlet 甚至可能不会读取 contextConfigLocation,但即使读取,我认为此时 bean 已经被声明,太糟糕了,父上下文拥有它们。

现在,另一个技巧......为了获得我的 DAO,我无法 @Autowired 它。我不得不通过 XML 手动注入(inject)它:
    <bean id="userAuthenticationProvider" class="com.company.app.security.UserAuthenticationProvider">
<property name="userDao" ref="userDao" />
</bean>

当然,我在我的 dao 上创建了 getter 和 setter 方法,瞧!我不知道为什么 @Autowired 在这里不起作用。我认为这是设计使然。也许这是 SecurityContext 特有的(它不会从其他上下文中提取),或者@Autowired 通常只从当前上下文中提取,或者可能因为我通过 XML 创建了 bean,我还必须通过 xml 和不是通过注释? (注释已启用并在我的顶级应用程序命名空间中工作)。

无论如何..仍然有很多我不明白,但重要的是它终于起作用了。

最佳答案

如果你打算使用 Spring MVC,你肯定需要 understand Spring MVC's ApplicationContext hierarchy .您还应该了解有关 basic components and lifecycles in a servlet container 的一些信息。 ,因为您似乎也对监听器和 servlet 的工作方式感到困惑。

简要说明您的情况:

  • 您正在创建两个 ApplicationContext:根上下文和 DispatcherServlet 上下文。根上下文由 ContextLoaderListener 根据在 contextConfigLocation 中命名的文件创建。此上下文旨在包含构成应用程序核心逻辑的 bean。 DispatcherServlet 上下文在该 servlet 启动时创建,并基于名为“webapp-servlet.xml”的文件。此上下文旨在包含支持与其关联的 DispatcherServlet 实例的任何 bean,并且其中应仅包含与 View 相关的 bean。
  • DispatcherServlet 上下文成为根上下文的子级。这允许将根上下文中的核心 bean 注入(inject)到 View 层 bean 中。可见性是一种方式。 View 层 bean 不可用于核心 bean,这是可取的。这就是为什么您的 DAO 无法注入(inject)您的身份验证提供程序的原因。 DAO 在子上下文中。
  • 基于注解的服务仅适用于它们被声明的上下文。如果@Autowired 不适用于特定 bean,那是因为您尚未声明 <context:component-scan/> <context:annotation-config/> 在该 bean 存在的上下文中。
  • 关于security - 在父上下文与子上下文中声明 Spring Bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7746633/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com