1

In my custom user details service, my variable "aUserService" doesnt auto wire even already annotated. tried a lot method, but still failed and the value is null.

Acutally i follow from krams tutorial. http://krams915.blogspot.sg/2012/01/spring-security-31-implement_1244.html

here is my project https://skydrive.live.com/#cid=837EF1FA9A4C06AE&id=837EF1FA9A4C06AE%21130 ,enviroment: netbeans 7.2,maven,tomcat 7.0.39,postgresql 9.2,db sql inside the project. db pool defined at META-INF/context.xml

here is my 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>

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

my custom user detail service

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

my user service implement

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) {
        ........
    }


}

my user class

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;
    }
    ......

}

my user interface

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

import ....;

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


public interface UserService {
    public List<User> findAll();
    ......;
}
Stupidfrog
  • 2,042
  • 6
  • 25
  • 35

4 Answers4

2

Problems Solved. 2 reasons caused it.

  1. remove <debug/> from security xml https://jira.springsource.org/browse/SEC-1885

  2. put org.springframework.web.servlet.view.InternalResourceViewResolver class in spring-servlet.xml(previously i put in application context xml).

NOW:

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

my 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>
Stupidfrog
  • 2,042
  • 6
  • 25
  • 35
0

You did not defined UserService aUserService in my root-context.xml.You have to define it like

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

or

add @Service annotation in UserService implementation class.So it will work.

Ruju
  • 961
  • 1
  • 12
  • 24
  • i put , but still null – Stupidfrog May 20 '13 at 06:13
  • actuall is but got error – Stupidfrog May 20 '13 at 06:23
  • org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accountController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private sg.com.innovax.opscentralv5.table.service.UserService sg.com.innovax.opscentralv5.AccountController.userService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [...table.service.UserService] is defined: expected single matching bean but found 2: [jpaUserService, aUserService] – Stupidfrog May 20 '13 at 06:34
  • change name aUserService to different ,you used it more than one time,it must be unique.Also you are using maven? – Ruju May 20 '13 at 06:35
  • instead of aUserService use jpaUserService as you defined Service("jpaUserService") and remove – Ruju May 20 '13 at 06:51
  • u means using @Service("jpaUserService") instead of @Service in my custom user details service? if so, still got error – Stupidfrog May 20 '13 at 07:01
  • the error is org.springframework.web.context.ContextLoader - Context initialization failed org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [root-context.xml]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'jpaUserService' for bean class [...impl.UserServiceImpl] conflicts with existing, non-compatible bean definition of same name and class [..CustomUserDetailsService] – Stupidfrog May 20 '13 at 07:02
  • do you have setter for the field you try to inject? – Evgeni Dimitrov May 20 '13 at 07:02
  • either you use service annotation or not both on same time – Ruju May 20 '13 at 07:03
  • to Evgeny, i dont have setter, if need, how to set it? to Rujvendra, both tried and not at same time..... – Stupidfrog May 20 '13 at 07:10
  • i think you defined jpaUserService for UserServiceImpl and CustomUserDetailsService check this and make unique – Ruju May 20 '13 at 07:15
  • headache..... here is my project https://skydrive.live.com/#cid=837EF1FA9A4C06AE&id=837EF1FA9A4C06AE%21130 ,enviroment: netbeans 7.2,maven,tomcat 7.0.39,postgresql 9.2,db sql inside the project. db pool defined at META-INF/context.xml – Stupidfrog May 20 '13 at 07:40
0

Based on your initial setup the following should work:

Since you specify a name for the bean creation in the @Service("jpaUserService") (http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/stereotype/Service.html) the name of the bean created from annotation scanning is referenced by this name. So you can reference it using that name. For that do the following:

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

Getters and setters are not necessary based on the following https://stackoverflow.com/a/634754/2319179.

Community
  • 1
  • 1
Carsten
  • 1,511
  • 2
  • 13
  • 24
0

Problem: The autowiring fails because by spring creates proxies using JDK-Dynamic proxies by default (which creates a proxy that implements the interface(s) of the target class). CGLIB-based proxy on the other hand is a subclass of the target class. See: What is the difference between JDK dynamic proxy and CGLib? To enable CGLIB based proxying annotate one of your @Configuration classes with

@EnableAspectJAutoProxy(proxyTargetClass=true):
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig 

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

And add : org.aspectj aspectjweaver 1.8.9

if necessary