AbstractSecurityWebApplicationInitializer与AbstractAnnotationConfigDispatcherServletInitializer

时间:2014-03-17 05:34:19

标签: java spring spring-mvc spring-security

我正在尝试为基于Spring 3.2.8的纯Java配置应用程序添加安全性。我按照说明http://docs.spring.io/spring-security/site/docs/3.2.2.RELEASE/reference/htmlsingle/#jc

我已经完成了3.1节,文档说此时每个URL都需要身份验证,但没有一个(至少我可以加载每个URL)。它说它创建了一个Servlet过滤器等。

很明显,WebSecurityConfigurerAdapter子类本身是不够的。所以我看一下3.1.1节,它说下一步是将springSecurityFilterChain注册到WAR,然后继续说明在Servlet 3+环境中,我需要继承AbstractSecurityWebApplicationInitializer。但我已经在继承AbstractAnnotationConfigDispatcherServletInitializer。我应该有一个吗?在AbstractSecurityWebApplicationInitializer JavaDoc中有一些关于排序的讨论,暗示我应该有多个初始化类。

在所有这些中,它还说要将WebSecurityConfigurerAdapter子类添加到getRootConfigClasses()(尽管该示例没有显示其他Spring启动文档的“AppConfig”;而且,仅此一项还不够)。

所以我尝试添加另一个初始化类。我的所有其他类都是我的AbstractAnnotationConfigDispatcherServletInitializer子类的公共静态内部类,所以我把另一个放在那里作为AbstractSecurityWebApplicationInitializer子类(而不是创建一个单独的.java文件)。

WARNING com.caucho.server.webapp.WebApp setConfigException: java.lang.UnsupportedOperationException: unimplemented
at com.caucho.server.webapp.ServletContextImpl.setSessionTrackingModes(ServletContextImpl.java:552)
at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.onStartup(AbstractSecurityWebApplicationInitializer.java:120)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:174)
at com.caucho.server.webapp.WebApp.callInitializer(WebApp.java:3471)
at com.caucho.server.webapp.WebApp.callInitializers(WebApp.java:3439)
at com.caucho.server.webapp.WebApp.startImpl(WebApp.java:3661)
at com.caucho.server.webapp.WebApp$StartupTask.run(WebApp.java:5196)
at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:173)
at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118)

我尝试添加订购无济于事。我的整个配置:

    package com.latencyzero.satdb.web;


//
//  Java Imports
//

import java.util.Properties;
import java.util.ResourceBundle;

import javax.naming.InitialContext;
import javax.servlet.ServletContext;
import javax.sql.DataSource;

//
//  Library Imports
//


import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.xml.DOMConfigurator;

import org.hibernate.SessionFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

import org.springframework.stereotype.Controller;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

//
//  Project Imports
//


/**
    There are still some things that get configured in the container. This app
    was developed using Resin. Things configured in resin's XML config for this
    app include the data source, error page, key store password for Apple
    Push Notifications (which should move to the DB).
*/

public
class
WebappInitializer
    extends
        org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer
{
    @Override
    protected
    Class<?>[]
    getRootConfigClasses()
    {
        Class<?>[] classes = { AppConfig.class, SecurityConfig.class };
        return classes;
    }

    @Override
    protected
    Class<?>[]
    getServletConfigClasses()
    {
        Class<?>[] classes = { WebConfig.class };
        return classes;
    }

    @Override
    protected
    java.lang.String[]
    getServletMappings()
    {
        String[] mappings = { "/" };
        return mappings;
    }

    @Override
    protected
    javax.servlet.Filter[]
    getServletFilters()
    {
        return new javax.servlet.Filter[]
        {
            new org.springframework.orm.hibernate3.support.OpenSessionInViewFilter(),
        };
    }

    /** *******************************************************************************************************************
        App context configuration.

        Hibernate config (data access, transactions, data model).
    */

    @Configuration
    @EnableAsync
    @EnableTransactionManagement
    @ComponentScan(basePackages = { "com.mymodelanddao", })
    public
    static
    class
    AppConfig
    {
        @Bean
        public
        org.springframework.jndi.JndiObjectFactoryBean
        dataSource()
        {
            org.springframework.jndi.JndiObjectFactoryBean bean = new org.springframework.jndi.JndiObjectFactoryBean();
            bean.setJndiName("java:comp/env/jdbc/db");
            return bean;
        }

        @Bean
        public
        org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
        sessionFactory()
        {
            DataSource dataSource = (DataSource) dataSource().getObject();

            org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean bean = new org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean();
            bean.setDataSource(dataSource);
            //  TODO: Do we need to scan this, since it's done as part of @ComponentScan?
            bean.setPackagesToScan(new String[] {"com.latencyzero.satdb.model"});

            Properties props = new Properties();
            props.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
            props.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider");
            props.setProperty("hibernate.jdbc.batch_size", "200");
            props.setProperty("hibernate.show_sql", "false");
            props.setProperty("hibernate.format_sql", "true");
            props.setProperty("hibernate.use_sql_comments", "false");
            props.setProperty("hibernate.generate_statistics", "true");
            bean.setHibernateProperties(props);

            return bean;
        }

        @Bean
        public
        PlatformTransactionManager
        transactionManager()
        {
            SessionFactory sf = sessionFactory().getObject();
            org.springframework.orm.hibernate3.HibernateTransactionManager bean = new org.springframework.orm.hibernate3.HibernateTransactionManager();
            bean.setSessionFactory(sf);
            return bean;
        }

        private static  Logger              sLogger                     =   Logger.getLogger(AppConfig.class);
    }

    /** *******************************************************************************************************************
        Web context configuration.
    */

    @Configuration
    @EnableWebMvc
    @ComponentScan(basePackageClasses = { com.mycontrollerclasses })
    public
    static
    class
    WebConfig
        extends
            org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
    {
        @Bean
        public
        InternalResourceViewResolver
        getInternalResourceViewResolver()
        {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix("/WEB-INF/jsp/");
            resolver.setSuffix(".jsp");
            return resolver;
        }

        @Bean
        public
        org.springframework.web.multipart.commons.CommonsMultipartResolver
        multipartResolver()
        {
            return new org.springframework.web.multipart.commons.CommonsMultipartResolver();
        }

        @Override
        public
        void
        addResourceHandlers(ResourceHandlerRegistry inRegistry)
        {
            inRegistry.addResourceHandler("/assets/**").addResourceLocations("/assets/").setCachePeriod(31556926);
            inRegistry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
            inRegistry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
        }

        private static  Logger              sLogger                     =   Logger.getLogger(WebConfig.class);
    }

    /** *******************************************************************************************************************
        Security configuration.
    */

    @Configuration
    @EnableWebMvcSecurity
    public
    static
    class
    SecurityConfig
        extends
            org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
    {
        @Autowired
        public
        void
        configureGlobal(AuthenticationManagerBuilder inAuth)
            throws
                Exception
        {
            sLogger.warn("configureGlobal =================================================");
            inAuth
                .inMemoryAuthentication()
                .withUser("user")
                .password("password")
                .roles("USER");
        }

        private static  Logger              sLogger                     =   Logger.getLogger(SecurityConfig.class);
    }

    public
    static
    class
    SecurityWebApplicationInitializer
        extends
            org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer
    {
    }
}

2 个答案:

答案 0 :(得分:1)

根据https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#abstractsecuritywebapplicationinitializer-with-spring-mvc,您必须引入第二个WebApplicationInitializer,通常派生自AbstractSecurityWebApplicationInitializer

第二个WebApplicationInitializer会将属性注册为springFilterChain

答案 1 :(得分:0)

使用5.0.6 Spring Security版本进行回答:

  1. @EnableWebSecurity已经包含@Configuration,因此
    同时指定两者都是多余的
  2. 您确实确实需要第二个appinitializer,它扩展了AbstractSecurityWebApplicationInitializer。您的一个似乎还可以
  3. 您的getRootConfigClasses也可以。
    您确实应该在那里注册SecurityConfig.class。

您的想法和配置似乎正确,但我不确定是否将SecurityWebApplicationInitializer保留为静态内部类是否允许Spring查找它。可能是个问题。我按照上述说明进行了所有配置,并且一切正常,将我重定向到“ / login”页面。