0

我正在尝试将 Shiro 1.2.2 与我的 SpringMVC 3.2.3 一起使用,我已经看到了几个如何使用 ini 文件配置 Shiro 的示例。但是我们使用的是 JavaConfig,我只找到了一个部分示例。我有几个@Configuration 文件:

public class EdmWebInitializer implements WebApplicationInitializer {

    private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
    private static final String DISPATCHER_SERVLET_MAPPING = "/*";

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
    root.scan( "com.company.config" );
    root.register( EdmConfiguration.class, SecurityConfig.class );
    servletContext.addListener( new ContextLoaderListener( root ) );

    ServletRegistration.Dynamic appServlet = servletContext.addServlet( DISPATCHER_SERVLET_NAME,
            new DispatcherServlet( root ) );
    appServlet.setLoadOnStartup( 1 );

    Set<String> mappingConflicts = appServlet.addMapping( DISPATCHER_SERVLET_MAPPING );
    servletContext
            .addFilter( "shiroFilter", new DelegatingFilterProxy( "shiroFilter", root ) )
            .addMappingForUrlPatterns( null, false, DISPATCHER_SERVLET_MAPPING );

    servletContext.addFilter( "Spring OpenEntityManagerInViewFilter",
            org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.class ).addMappingForUrlPatterns(
            null, false, "/*" );

我的 bean 在这里定义:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.company.service", "com.company.utility",
        "com.company.controller", "com.company.utility.startup",
        "com.company.security", "com.company.security.model" })
@EnableTransactionManagement
@ImportResource({ "classpath:applicationContext.xml"})
@PropertySource({ "classpath:application.properties", "classpath:mail.properties" })
public class EdmConfiguration extends WebMvcConfigurationSupport {


    @Resource
    private Environment environment;

    @Autowired
    private org.apache.shiro.web.mgt.WebSecurityManager securityManager;

    @Bean
    public DataSource dataSource() {
        BoneCPDataSource dataSource = new BoneCPDataSource();

    ...
        return dataSource;
    }

    @Bean
    public JpaTransactionManager transactionManager() throws ClassNotFoundException {
        JpaTransactionManager transactionManager = new JpaTransactionManager();

        transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() );

        return transactionManager;
    }

    @Bean
    public DelegatingFilterProxy springSecurityFilterChain() {
        return new DelegatingFilterProxy();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws ClassNotFoundException {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();

        entityManagerFactoryBean.setDataSource( dataSource() );
        entityManagerFactoryBean.setPackagesToScan( environment
                .getRequiredProperty( PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN ) );
        entityManagerFactoryBean.setPersistenceProviderClass( HibernatePersistence.class );

        Properties jpaProperties = new Properties();
        ...
        entityManagerFactoryBean.setJpaProperties( jpaProperties );

        return entityManagerFactoryBean;
    }

    @Bean
    public PersistenceExceptionTranslator exTranslator() {
        return new HibernateExceptionTranslator();
    }

    @Bean(initMethod = "init")
    public StartupListener startupListener() {
        return new StartupListener();
    }




    @Bean
    public ContentNegotiationManagerFactoryBean contentNegotiationManager() {
        Properties properties = new Properties();
        properties.setProperty( "xml", "application/xml" );
        properties.setProperty( "json", "application/json" );
        properties.setProperty( "html", "application/html" );

        ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
        contentNegotiationManager.setFavorParameter( true );
        contentNegotiationManager.setMediaTypes( properties );
        contentNegotiationManager.setDefaultContentType( MediaType.APPLICATION_JSON );

        return contentNegotiationManager;
    }



    @Bean
    public JavaMailSenderImpl mailSender() {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        int port = Integer.parseInt( environment.getRequiredProperty( "mail.smtp.socketFactory.port" ) );
        mailSender.setHost( environment.getRequiredProperty( "mail.smtp.host" ) );
        mailSender.setPort( port );
        mailSender.setUsername( environment.getRequiredProperty( "mail.login.username" ) );
        mailSender.setPassword( environment.getRequiredProperty( "mail.login.password" ) );

        Properties properties = new Properties();
        properties.setProperty( "mail.smtp.auth", environment.getRequiredProperty( "mail.smtp.auth" ) );
        properties.setProperty( "mail.smtp.starttls.enable", "true" );
        mailSender.setJavaMailProperties( properties );

        return mailSender;
    }


    @Bean
    public VelocityEngine getVelocityEngine() throws VelocityException, IOException {
        VelocityEngineFactory factory = new VelocityEngineFactory();
        Properties props = new Properties();
        props.put( "resource.loader", "class" );
        props.put( "class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" );
        factory.setVelocityProperties( props );
        factory.setResourceLoaderPath( "/com/edelweissco/dental/templates" );
        factory.setPreferFileSystemAccess( false );
        return factory.createVelocityEngine();
    }

    @Bean
    public StandardPasswordEncoder encoder() {
        return new org.springframework.security.crypto.password.StandardPasswordEncoder();
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter() {
        ShiroFilterFactoryBean shiroFilter = new org.apache.shiro.spring.web.ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager( securityManager);
        return shiroFilter;
    }

    @Bean
    @DependsOn(value = "lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true); // it's false by default
        return creator;
    }

我已将 Shiro 配置分解为自己的文件:

    @Configuration
public class SecurityConfig {

    @Bean
    public CustomSecurityRealm customSecurityRealm() {
        return new CustomSecurityRealm();
    }

    @Bean
    public SaltAwareJdbcRealm saltAwareJdbcRealm() {
        return new SaltAwareJdbcRealm();
    }

    @Bean
    public org.apache.shiro.authc.credential.DefaultPasswordService passwordService() {
        return new DefaultPasswordService();
    }

    @Bean
    public TempFixPasswordMatcher passwordMatcher() {
        TempFixPasswordMatcher tempFixPasswordMatcher = new TempFixPasswordMatcher();
        tempFixPasswordMatcher.setPasswordService( passwordService() );
        return tempFixPasswordMatcher;
    }


    @Bean
    public WebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm( saltAwareJdbcRealm() );
        return securityManager;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public MethodInvokingFactoryBean methodInvokingFactoryBean() {
        MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
        methodInvokingFactoryBean.setStaticMethod( "org.apache.shiro.SecurityUtils.setSecurityManager" );
        methodInvokingFactoryBean.setArguments( new Object[]{ securityManager() } );
        return methodInvokingFactoryBean;
    }

    @Bean
    @DependsOn(value = "lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager( securityManager() );
        return authorizationAttributeSourceAdvisor;
    }

当我尝试部署时,会出现以下异常:

这是我从 OfficeService 中删除 @Transaction 后得到的完整堆栈跟踪:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'menuService': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'menuRepository': Post-processing of the FactoryBean's object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy68]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy68
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:306)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1116)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
    at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1551)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:835)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:771)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:622)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:569)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:835)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:771)
    at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1455)
    at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:75)
    at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1296)
    at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1388)
    at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:819)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:303)
    at sun.rmi.transport.Transport$1.run(Transport.java:159)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:680)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'menuRepository': Post-processing of the FactoryBean's object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy68]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy68
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:165)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:102)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1454)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:442)
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550)
    at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
    ... 55 more
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy68]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy68
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:217)
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:111)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:477)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:409)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1625)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:162)
    ... 65 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy68
    at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
    at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
    at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
    at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285)
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205)
    ... 72 more
Nov 9, 2013 4:10:04 PM org.apache.catalina.core.ApplicationContext log
INFO: Closing Spring root WebApplicationContext
4

1 回答 1

5

大概您的服务类上有一些@RequiresAuthentication@RequiresRole注释。为了启用这些,Shiro (Spring) 必须代理它创建的 bean。它对DefaultAdvisorAutoProxyCreatorbean 执行此操作。但是,此 bean 代理与 JDK 代理一起创建基于接口而不是基类的代理。

例如,假设 Spring 必须代理OfficeService,它将创建一个java.lang.reflect.Proxy包装OfficeServicebean 的实例。如果你调用getClass()这个对象,它会返回类似com.sun.proxy.$Proxy64. 如果您OfficeService正在实现任何接口,则该对象将是这些接口的实例。但是,bean 不是 的实例OfficeService,因此 Spring 不能将其用作@Autowired目标。

相反,您必须告诉 Spring 使用 CGLIB 代理。您可以通过在此处更改配置来做到这一点

@Bean
@DependsOn(value = "lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
    creator.setProxyTargetClass(true); // it's false by default
    return creator;
}

并将 CGLIB 库(jars)添加到您的类路径中。


请注意,如果这不是 Shiro 问题,您需要发布其余的配置。如果您在上下文中进行任何其他代理,则需要执行类似的操作来禁用 JDK 代理。

似乎可以创建代理的唯一其他事情是事务管理,因此更改为

@EnableTransactionManagement(proxyTargetClass = true)
于 2013-11-08T04:16:48.607 回答