结合 DispatcherServlet、ContextLoaderListener 和 SpringSecurity

Posted

技术标签:

【中文标题】结合 DispatcherServlet、ContextLoaderListener 和 SpringSecurity【英文标题】:Combining DispatcherServlet, ContextLoaderListener and SpringSecurity 【发布时间】:2012-06-14 09:43:43 【问题描述】:

我有一个难题要解决。一直在尝试将上述 3 种技术集成到我们的 web 应用程序中。我们想使用

    春季网络 Spring MVC 作为视图技术(使用 freemarker) Spring Security 作为安全层

但无论我如何配置我的 web.xml 和其他上下文文件,我都无法让所有内容同时工作。使用我当前的配置,一切都会正常工作,除了 SpringSecurity 不会拦截 URL 模式

一些谷歌搜索(和常识)告诉我,结合 DispatcherServlet 和 ContextLoaderListener 可能是个问题。

所以这是我的配置。 (抱歉,文字太多,感谢阅读):

web.xml:

<!-- Needed by Spring -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/dw-manager-context.xml</param-value>
</context-param>

<!-- Needed by Spring MVC -->
<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!-- Needed by Spring Security -->
<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>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

我的 servlet-context.xml:

<!-- Scan for controllers -->
<context:component-scan base-package="dw.manager" />

<!-- Need to declare annotation driven transactions again so they are picked up above controller methods -->
<tx:annotation-driven transaction-manager="transactionManager" />

<mvc:annotation-driven />

<bean id="viewResolver"     class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
    <!-- ... -->
</bean>

<bean id="freemarkerConfig"
    class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
    <!-- ... -->
</bean>

我的经理-context.xml:

<context:annotation-config />   

    <!-- deployment-setup just loads properties (files) -->
<import resource="deployment-setup.xml" />
<import resource="spring-security-context.xml" />
<import resource="dw-manager-datasource.xml" />

<!-- Import sub-modules -->
<import resource="classpath:dw-security-context.xml" />
<!-- ... -->

Spring-Security-context.xml:

<http pattern="/login" security="none" />
<http pattern="/accessDenied" security="none" />
<http pattern="/" security="none" />

<!-- enable use of expressions, define URL patterns and login/logout forms 
    and targets) -->
<http use-expressions="true" access-denied-page="/accessDenied">
    <intercept-url pattern="/*" access="hasRole('ROLE_USER')" />
    <!-- more stuff -->
</http>

<!-- a lot more... -->

manager-datasource 只是设置数据库...


感谢您阅读所有内容并希望对我有所帮助.. ;)


编辑:更多信息

我不能只跳过 ContextLoaderListener,它是 SpringSecurity 所要求的。我也不能跳过 contextConfigLocation,因为这是 ContextLoaderListener 所需的上下文。我只是自己定义名称,否则它将搜索 applicationContext.xml。也许我可以添加一个空的 contextConfigLocation?但这可能只是意味着,底层模块不会找到要注入的 bean..?


edit2

我认为主要问题是 SpringSecurity 需要一个 webapp 上下文 (ContextLoaderListener) 才能工作,但 web 应用程序在 servlet 上下文中运行。控制器方法由 servlet 上下文映射,因此在 servlet 上下文“外部”运行的 spring security 不会收到事件通知,并且过滤器不会启动..

【问题讨论】:

你能告诉我,如果你像/test一样发出请求会发生什么,它是去控制器还是被重定向到登录页面? 2012-06-11 15:31:23 PageNotFound [WARN] No mapping found for HTTP request with URI [/dw-manager/test] in DispatcherServlet with name 'appServlet' 如果你给出一个有效的 url 返回的响应是什么? 如果我输入 /login 它将转到映射“/login”的控制器方法,然后返回登录页面。但是“/home”是一个现有的页面,应该受到 SpringSecurity (&lt;intercept-url pattern="/*") 的保护。它还有一个 @PreAuthorize 被忽略的注释......如果我忘记了什么,Spring security 甚至不会像往常一样抱怨它没有安全上下文.. 我认为要使PreAutherize 工作,您需要启用&lt;global-method-security&gt; 【参考方案1】:

叹息..我不知道为什么它第一次没有工作,可能是错误的解决方案在尝试正确的解决方案时在缓存中..但是它现在就像我发布的那样工作。感谢 Arun 抽出宝贵时间。

现在唯一的问题:spring-test-mvc 不支持 Spring Security 的 FilterChain 但这是另一个问题..

【讨论】:

以上是关于结合 DispatcherServlet、ContextLoaderListener 和 SpringSecurity的主要内容,如果未能解决你的问题,请参考以下文章

Initializing Spring DispatcherServlet dispatcherServlet

Initializing Spring DispatcherServlet dispatcherServlet

Initializing Spring DispatcherServlet dispatcherServlet

理解DispatcherServlet

关于DispatcherServlet的一些说明

具有多个 DispatcherServlet 的 Spring Boot,每个 DispatcherServlet 都有自己的 @Controller