如何同时为 Spring Security 正确定义 web.xml 和基于 java 的配置

Posted

技术标签:

【中文标题】如何同时为 Spring Security 正确定义 web.xml 和基于 java 的配置【英文标题】:How to correctly define web.xml and java-based config for Spring Security at the same time 【发布时间】:2017-02-08 16:20:25 【问题描述】:

我的项目完全基于基于 java 的配置。所以不是标准的 web.xml 我有这个:

public class MyWebAppInitializer implements WebApplicationInitializer 

    @Override
    public void onStartup(ServletContext container) throws ServletException 
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
          rootContext.register(WebAppConfiguration.class);
          AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();

          ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
          dispatcher.setLoadOnStartup(1);
          dispatcher.addMapping("/");
    

效果很好,我能够像这样在 Thymeleaf 模板中获取 csrf 令牌:

<meta name="_csrf" th:content="$_csrf.token"/>
<meta name="_csrf_header" th:content="$_csrf.headerName"/>

但是现在我需要将我的项目部署到 Google App Engine,并且它需要有 web.xml,否则它甚至无法启动。 我添加了 web.xml,并删除了上面的 java 配置:

<context-param>
        <param-name>contextClass</param-name>
        <param-value>
        org.springframework.web.context.support.AnnotationConfigWebApplicationContext
    </param-value>
    </context-param>

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

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.demshin.medpro.configuration.WebAppConfiguration</param-value>
    </context-param>

    <servlet>
        <servlet-name>springServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

当我尝试打开我的应用程序的 url 时,我得到一个异常:

org.thymeleaf.exceptions.TemplateProcessingException:异常 评估 SpringEL 表达式:“_csrf.token”

我认为,问题出在过滤器链损坏。 但如果我将它添加到 web.xml:

<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>

而不是这个 java 配置:

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer 
    public SecurityWebApplicationInitializer() 
        super(WebSecurityConfiguration.class);
    

,问题仍然存在,但痕迹有点不同。

那么如何才能治愈呢?也许有办法摆脱 Google App Engine 上的 web.xml? 谢谢。

【问题讨论】:

【参考方案1】:

我发现了一些有用的信息here。 问题是 WebApplicationInitializer 需要 Servlet 3.0,而 Appengine 只支持 Servlet 2.5。所以我们必须使用基于 XML 的配置,至少在初始化时是这样。并在 web.xml 中手动配置 Spring 过滤器/servlet。 不幸的是,在没有将 spring 配置完全移动到 xml 的情况下,我未能使其工作,只是添加 spring-security.xml 不起作用。

我们也可以投票支持 Servlet 3.0 here,但不幸的是,Google 似乎没有任何添加它的计划。

【讨论】:

【参考方案2】:

如果你保留 java 配置,然后创建一个空的 web.xml,例如

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">

</web-app>

【讨论】:

以上是关于如何同时为 Spring Security 正确定义 web.xml 和基于 java 的配置的主要内容,如果未能解决你的问题,请参考以下文章

如何确定使用 Spring Security 访问 URL 需要哪些角色?

如何在 Spring Security 中编辑定时注销

使用 spring security 确定 JSP 中的安全 url

如何在 Spring Boot 应用程序中包含 Spring Security

Spring Security:同时授权两个或多个 Web 应用程序

如何使用xml在spring security中禁用注销确认?