在 Spring 中在嵌入式 Jetty 上配置 Spring Security

Posted

技术标签:

【中文标题】在 Spring 中在嵌入式 Jetty 上配置 Spring Security【英文标题】:Configure Spring Security on embedded Jetty in Spring 【发布时间】:2011-10-02 23:13:52 【问题描述】:

我有一个 Spring beans 定义文件,如下

<bean id="jettyZk" class="org.eclipse.jetty.server.Server" init-method="start" destroy-method="stop">
    <!-- properties, threadPool, connectors -->

    <property name="handler">
        <bean class="org.eclipse.jetty.servlet.ServletContextHandler">
            <property name="eventListeners">
                <list>
                    <!-- my.ContextLoaderListener
                    * An ApplicationContextAware ContextLoaderListener that allows for using the current ApplicationContext,
                    * as determined by ApplicationContextAware, as the parent for the Root WebApplicationContext.
                    * 
                    * Also provides for specifying the contextConfigLocation of the Root WebApplicationContext, because
                    * Eclipse Jetty 7 ServletContextHandler does not expose a setInitParameters method.
                    -->
                    <bean class="my.ContextLoaderListener">
                        <property name="contextConfigLocation" value="/META-INF/spring/applicationContext-securityZk.xml"/>
                    </bean>
                    <!-- not sure if this is needed, disabled for now -->
                    <!-- <bean class="org.springframework.web.context.request.RequestContextListener"/> -->
                </list>
            </property>
            <property name="servletHandler">
                <bean class="org.eclipse.jetty.servlet.ServletHandler">
                    <property name="filters">
                        <list>
                            <bean class="org.eclipse.jetty.servlet.FilterHolder">
                                <property name="name" value="springSecurityFilterChain"/>
                                <property name="filter">
                                    <bean class="org.springframework.web.filter.DelegatingFilterProxy"/>
                                </property>
                            </bean>
                        </list>
                    </property>
                    <!-- filterMappings, servlets, servletMappings -->
                </bean>
            </property>
        </bean>
    </property>
</bean>

当尝试启动上下文时,我得到以下异常

Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: ServletContext must not be null

Caused by: java.lang.IllegalArgumentException: ServletContext must not be null
    at org.springframework.util.Assert.notNull(Assert.java:112)
    at org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(WebApplicationContextUtils.java:109)

这是使用 Spring 3.0.5.RELEASE

异常是可以理解的,看DelegatingFilterProxy#findWebApplicationContext的代码和JavaDocs,上面写着

WebApplicationContext 必须已经加载并存储在 此过滤器被初始化(或调用)之前的 ServletContext。

因为我试图将过滤器创建为上下文处理程序的(子)属性,所以上下文尚未初始化似乎是明智的,因此 Spring WAC 也没有。

我想知道的是如何在 Spring 本身组装的嵌入式 Jetty 容器中配置 Spring Security?

似乎有一个 catch 22 场景,只需要后期初始化,但我找不到合适的标志来玩弄。我已经尝试将lazy-init="true" 设置到过滤器 bean 上,但这似乎并没有起到太大作用,这并不奇怪。

相关: How to embed Jetty into Spring and make it use the same AppContext it was embedded into?

【问题讨论】:

由于试图解决这个问题,我一直在研究 Spring JavaConfig,并且有一个相关的问题:***.com/questions/6683771/… 你有没有想出办法做到这一点?我有基本相同的问题。 我最终得到了一个基于 @Configuration 的设置 我正在处理类似的问题,您能指出任何好的信息来源或示例吗? 【参考方案1】:

我正在运行 Jetty 6.1.4 和 Spring 3.0.5,但我使用的是老式的方式,使用 WEB-INF/web.xml。

使用这种方法,它会导致零问题。

public class JettyServer 

    public static void main(String[] args) throws Exception 
    Properties props = new Properties();
    props.load(new FileInputStream("./etc/server.properties"));

    Server server = new Server();

    final String configFile = props.getProperty("server.config");

    XmlConfiguration configuration = 
        new XmlConfiguration(new File(configFile).toURI().toURL());
    configuration.configure(server);
    HandlerCollection handlers = new HandlerCollection();

    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath(props.getProperty("context.path"));
    webapp.setDefaultsDescriptor(props.getProperty("default.config"));

    webapp.setWar(props.getProperty("war.path"));

    NCSARequestLog requestLog = new NCSARequestLog(props.getProperty("log.file"));
    requestLog.setExtended(true);
    RequestLogHandler requestLogHandler = new RequestLogHandler();
    requestLogHandler.setRequestLog(requestLog);

    handlers.setHandlers(
       new Handler[]  webapp, new DefaultHandler(), requestLogHandler );

    server.setHandler(handlers);

    server.setStopAtShutdown(true);
    server.setSendServerVersion(true);

    server.start();
    server.join();

【讨论】:

你让 Jetty 提供一个 WAR 文件,这不是我正在做的。 思考我又花了几个小时左右调试它是如何被调用的,而且我在运行时没有可用的 org.eclipse.jetty.webapp 包,所以似乎无论我在哪里实例化 Spring过滤器 afterPropertiesSet 在我的 ServletContext 初始化之前被调用。我确实注意到我在错误的容器上设置了“过滤器”,所以我会更新问题中的示例,但我仍然卡住了。不过谢谢:)

以上是关于在 Spring 中在嵌入式 Jetty 上配置 Spring Security的主要内容,如果未能解决你的问题,请参考以下文章

Embedded Jetty 无法识别 Spring MVC 安全性

Spring 3.1 WebApplicationInitializer & Embedded Jetty 8 AnnotationConfiguration

Undertow和jetty做嵌入式,哪个更好

Jetty实战之 嵌入式运行Jetty 配置Https

Spring Boot 1.5.9和嵌入式jetty服务器在运行时抛出空指针异常?

Jetty 9.0 SPDY 嵌入式配置