Autowire在自定义UserDetailsS​​ervice中不起作用

时间:2013-05-20 04:21:31

标签: spring spring-mvc spring-security

在我的自定义用户详细信息服务中,我的变量“aUserService”即使已经注释也不会自动连接。尝试了很多方法,但仍然失败,值为null。

我正在遵循krams教程。 http://krams915.blogspot.sg/2012/01/spring-security-31-implement_1244.html

这是我的项目https://skydrive.live.com/#cid=837EF1FA9A4C06AE&id=837EF1FA9A4C06AE%21130,环境:netbeans 7.2,maven,tomcat 7.0.39,postgresql 9.2,db sql在项目中。在META-INF / context.xml

定义的数据库池

这是我的 的web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
        <filter>
            <filter-name>setEncoding</filter-name>
            <filter-class>sg.com.innovax.opscentralv5.objects.setEncoding</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>setEncoding</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!-- ================================ START Captha ================================ -->
        <filter>
            <filter-name>jcaptchaFilter</filter-name>
            <filter-class>sg.com.innovax.jcaptcha.JCaptchaFilter</filter-class>
            <init-param>
                <param-name>failureUrl</param-name>
                <param-value>/?error=true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>jcaptchaFilter</filter-name>
            <url-pattern>/jcaptcha.jpg</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>jcaptchaFilter</filter-name>
            <url-pattern>/j_spring_security_check</url-pattern>
        </filter-mapping>
        <!-- ================================ END Captha ================================ -->
        <!-- 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>
        </filter-mapping>
        <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/spring/root-context.xml
                /WEB-INF/spring/security.xml

            </param-value>
        </context-param>
        <!-- Creates the Spring Container shared by

 all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <!-- Processes application requests -->
    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <error-page>
    <error-code>401</error-code>
    <location>/WEB-INF/views/401.jsp</location>
    </error-page>
    <error-page>
    <error-code>403</error-code>
    <location>/WEB-INF/views/403.jsp</location>
    </error-page>
    <error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/views/404.jsp</location>
    </error-page>
    <error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/views/500.jsp</location>
    </error-page>    

    <resource-ref>
        <description>postgreSQL</description>
        <res-ref-name>jdbc/postgres</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

    <!-- solr server url  -->
    <context-param>
        <param-name>solr_url</param-name>
        <param-value>http://localhost:8080/solr</param-value>
    </context-param>
</web-app>

my spring servlet xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>
</beans:beans>

my security xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <debug />

    <global-method-security pre-post-annotations="enabled"/>

    <http pattern="/resources/**" security="none"/>
    <http pattern="/test/**" security="none"/>
    <http pattern="/loggedout.jsp" security="none"/>
    <http pattern="/forgotPassword" security="none"/>
    <http pattern="/ProcessResetPassword" security="none"/>
    <http pattern="/test" security="none"/>
    <http pattern="/jcaptcha.jpg" security="none"/>
    <http use-expressions="true">
        <intercept-url pattern="/" access="permitAll"/>
        <intercept-url pattern="/**" access="isAuthenticated()" />
        <form-login login-processing-url="/j_spring_security_check"
                    login-page="/"
                    default-target-url="/user/"
                    always-use-default-target="true"
                    authentication-failure-url="/?error=true" />
        <remember-me key="OpsCentral" token-validity-seconds="3600"/>
        <logout logout-url="/j_spring_security_logout" />
    </http>
    <context:annotation-config />

    <context:component-scan base-package="sg.com.innovax" />
    <authentication-manager >
        <authentication-provider user-service-ref="customUserDetailsService">
                    <password-encoder hash="sha"/>
            </authentication-provider>
    </authentication-manager>

    <!-- Jcaptcha -->
    <beans:bean id="captchaService"
        class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService">
        <beans:property name="captchaEngine">
            <beans:bean class="sg.com.innovax.jcaptcha.GMailEngine" />
        </beans:property>
        <!-- 180 secs to expired
        <property name="minGuarantedStorageDelayInSeconds" value="180" />
        -->
    </beans:bean>
 </beans:beans>

我的root-context xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
        xmlns:beans="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jdbc="http://www.springframework.org/schema/jdbc"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
                        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
                        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
            ">


<context:annotation-config />

<context:component-scan base-package="sg.com.innovax" />

    <mvc:annotation-driven />

<mvc:resources mapping="/resources/**" location="/resources/" />

    <tx:annotation-driven transaction-manager="transactionManager" />
<!-- Root Context: defines shared resources visible to all other web components -->
<jee:jndi-lookup id="dataSource"
    jndi-name="jdbc/postgres"
    expected-type="javax.sql.DataSource" />
    <beans:bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
    <beans:property name="defaultLocale" value="en" />
</beans:bean>
        <!-- Register the welcome.properties -->
<beans:bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource">
    <beans:property name="basename" value="welcome" />
</beans:bean>

        <!-- JPA -->
<beans:bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <beans:property name="dataSource" ref="dataSource" />
   <beans:property name="jpaVendorAdapter">
      <beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
         <beans:property name="database" value="POSTGRESQL" />
      </beans:bean>
   </beans:property>
   <beans:property name="packagesToScan" value="sg.com.innovax" />
   <beans:property name="jpaProperties">
       <beans:props>
            <beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</beans:prop>
            <beans:prop key="hibernate.show_sql">true</beans:prop>
       </beans:props>
   </beans:property>
 </beans:bean>

    <beans:bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <beans:property name="entityManagerFactory" ref="emf" />
 </beans:bean>

    <beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <beans:property name="maxUploadSize" value="100000000"/>
</beans:bean>

我的自定义用户详细信息服务

package sg.com.innovax.opscentralv5.objects;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sg.com.innovax.opscentralv5.table.service.UserService;

/**
 * A custom {@link UserDetailsService} where user information
 * is retrieved from a JPA repository
 */
@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
        private UserService aUserService;

    /**
     * Returns a populated {@link UserDetails} object. 
     * The username is first retrieved from the database and then mapped to 
     * a {@link UserDetails} object.
     */
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        try {
            sg.com.innovax.opscentralv5.table.User u = aUserService.findByUsername(username);

                        String pass = sg.com.innovax.opscentralv5.table.User.byteToHex(u.getPassword());

            boolean enabled = true;
            boolean accountNonExpired = true;
            boolean credentialsNonExpired = true;
            boolean accountNonLocked = true;

            return new User(
                    u.getUsername(), 
                    pass,
                    enabled,
                    accountNonExpired,
                    credentialsNonExpired,
                    accountNonLocked,
                    getAuthorities(1));

        } catch (Exception e) {
            System.out.println(e.toString());
            throw new RuntimeException(e);
        }
    }

    /**
     * Retrieves a collection of {@link GrantedAuthority} based on a numerical role
     * @param role the numerical role
     * @return a collection of {@link GrantedAuthority
     */
    public Collection<? extends GrantedAuthority> getAuthorities(Integer role) {
        List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role));
        return authList;
    }

    /**
     * Converts a numerical role to an equivalent list of roles
     * @param role the numerical role
     * @return list of roles as as a list of {@link String}
     */
    public List<String> getRoles(Integer role) {
        List<String> roles = new ArrayList<String>();

        if (role.intValue() == 1) {
            roles.add("ROLE_USER");
            roles.add("ROLE_ADMIN");

        } else if (role.intValue() == 2) {
            roles.add("ROLE_USER");
        }

        return roles;
    }

    /**
     * Wraps {@link String} roles to {@link SimpleGrantedAuthority} objects
     * @param roles {@link String} of roles
     * @return list of granted authorities
     */
    public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        for (String role : roles) {
            authorities.add(new SimpleGrantedAuthority(role));
        }
        return authorities;
    }
}

我的用户服务工具

package sg.com.innovax.opscentralv5.table.service.impl;

import .....;


@Service("jpaUserService")
@Repository
@Transactional
public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @PersistenceContext
    private EntityManager em;


    @Transactional(readOnly=true)
    public User findByUsername(String username) {
        ........
    }


}

我的用户类

package sg.com.innovax.opscentralv5.table;

import ....;

@Entity
@Table(name = "users", uniqueConstraints = { @UniqueConstraint(columnNames = "username") })
@NamedQueries({
    .....
})
public class User implements Serializable {

    public static final String ROLE_ADMIN = "ROLE_ADMIN";
    public static final String ROLE_USER = "ROLE_USER";

    @Id
    @SequenceGenerator(name="users_id_seq", sequenceName="users_id_seq", allocationSize=1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="users_id_seq")
    @Basic(optional = false)
    private Integer id;
    @Column(unique=true)
    private String username;
    private byte[] password;
    private String email;
    private String mobile;
    private Boolean enabled;
    private Timestamp deleted;
    @OneToOne(cascade=CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private Role role;



    public Integer getId() {
        return id;
    }
    ......

}

我的用户界面

package sg.com.innovax.opscentralv5.table.service;

import ....;

import sg.com.innovax.opscentralv5.table.User;


public interface UserService {
    public List<User> findAll();
    ......;
}

4 个答案:

答案 0 :(得分:2)

解决的问题。 造成它的原因有两个。

  1. 从安全xml中删除<debug/> https://jira.springsource.org/browse/SEC-1885

  2. 在spring-servlet.xml中放入org.springframework.web.servlet.view.InternalResourceViewResolver类(之前我放入应用程序上下文xml)。

  3. 现在:

    我的web.xml

    ......
        <servlet>
            <servlet-name>spring</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>spring</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    ......
    

    我的spring-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
        <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
            <property name="prefix" value="/WEB-INF/views/" />
            <property name="suffix" value=".jsp" />
        </bean>
    </beans>
    

答案 1 :(得分:0)

您没有在我的root-context.xml中定义UserService aUserService。您必须将其定义为

  <beans:bean id="aUserService" class=" UserService implementation classname">

在UserService实现类中添加@Service注释。这样就可以了。

答案 2 :(得分:0)

根据您的初始设置,以下内容应该有效:

由于您在@Service("jpaUserService")http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/stereotype/Service.html)中指定了bean创建的名称,因此通过此名称引用从注释扫描创建的Bean的名称。所以你可以用这个名字来引用它。为此,请执行以下操作:

@Autowired
@Qualifier("jpaUserService"")
private UserService aUserService;

根据以下https://stackoverflow.com/a/634754/2319179

,无需使用getter和setter

答案 3 :(得分:0)

问题: 自动装配失败是因为Spring默认使用JDK-Dynamic代理创建代理(它创建一个实现目标类接口的代理)。另一方面,基于CGLIB的代理是目标类的子类。 请参阅:JDK动态代理和CGLib之间有什么区别? 要启用基于CGLIB的代理,请使用

注释其中一个@Configuration类
@EnableAspectJAutoProxy(proxyTargetClass=true):
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig 

{     ... } - 请参阅:http://www.mzan.com/article/35525838-spring-security-config-autowiring-custom-userdetailsservice-bean.shtml#sthash.S3YwrKyC.dpuf

并添加:     org.aspectj     aspectjweaver     1.8.9

如有必要