1

It's apparently well documented that @Autowired won't work inside a UserDetailsService

Is this true? If not, how can I autowire inside my UserDetailsService?

If it is true, are there any work arounds? How can I execute a hibernate query?

The accountDao I bind in AccountService works fine if I put it in the application context and use it in any other class. I read somewhere that Autowire didn't work because the UserDetailsService was out of the scope where spring would bind? and that a work around was to manually wire it in xml. If that's true? How does that work?

AccountService:

@Service
public class AccountService implements UserDetailsService {

    @Autowired
    AccountDao accountDao;

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException, DataAccessException {

        Account account = accountDao.getUser(username);
        if (account == null)
            throw new UsernameNotFoundException("No account found for '"
                    + username + "'");

        return account;
    }

    @SuppressWarnings("unused")
    private GrantedAuthority[] getAuthorities(boolean isAdmin) {
        List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);
        authList.add(new GrantedAuthorityImpl("ROLE_USER"));
        if (isAdmin) {
            authList.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
        }
        return authList.toArray(new GrantedAuthority[] {});
    }

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

Security Context

<?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:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/security 
   http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <!-- This is where we configure Spring-Security -->
    <security:http auto-config="true" use-expressions="true"
        access-denied-page="/krams/auth/denied">

        <security:intercept-url pattern="/" access="permitAll" />
        <security:intercept-url pattern="/campaign/*"
            access="hasRole('ROLE_ADMIN')" />
        <!-- <security:intercept-url pattern="/city/*" access="hasRole('ROLE_ADMIN')"/> -->
        <security:intercept-url pattern="/company/*"
            access="hasRole('ROLE_ADMIN')" />
        <security:intercept-url pattern="/krams/main/common"
            access="hasRole('ROLE_USER')" />

        <security:form-login login-page="/auth/login"
            authentication-failure-url="/auth/login?error=true"
            default-target-url="/home" />

        <security:logout invalidate-session="true"
            logout-success-url="/auth/login" logout-url="/auth/logout" />

    </security:http>

    <!-- Declare an authentication-manager to use a custom userDetailsService -->
    <security:authentication-manager>
        <security:authentication-provider
            user-service-ref="customUserDetailsService">
            <security:password-encoder ref="passwordEncoder" />
        </security:authentication-provider>
    </security:authentication-manager>

    <!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the 
        database -->
    <bean
        class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"
        id="passwordEncoder" />


    <bean id="customUserDetailsService" class="com.groupdealclone.app.service.AccountService" />
    <bean id="accountDao" class="com.groupdealclone.app.dao.JdbcAccountDao" />




</beans>

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/root-context.xml
            /WEB-INF/spring/security-context.xml
        </param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!--    
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
     -->
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

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


    <filter>
        <filter-name>hibernateFilter</filter-name>
        <filter-class>
            org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
        </filter-class>
    </filter>

    <welcome-file-list>
        <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>

</web-app>
Peter Mularien
  • 2,578
  • 1
  • 25
  • 34
Ali
  • 12,354
  • 9
  • 54
  • 83
  • What errors are you getting when you try it? – beny23 Aug 16 '11 at 12:47
  • basically in `AccountService`, `accountDao` is null. Anything i autowire is null. If I declare new AccountDao() then EntityManager inside it is autowired and that is null. – Ali Aug 16 '11 at 12:59
  • 1
    If you are declaring the `UserDetailsService` implementation in your own bean context (how else would you do this?), `@Autowired` should work just fine. Do you have `` set up properly? Where are you seeing documentation that this doesn't work? – Peter Mularien Aug 16 '11 at 13:05
  • @Peter, The UserDetailsService is in the same package as all the other services and non of them have this problem. The only difference is that the beans for all the other services is in application-context where as UserDetailsService is on Spring-Context (aka root-context). I'll try moving scan packages to root level. – Ali Aug 16 '11 at 13:49
  • 2
    @Peter, that did it, coped component-scan line from `servlet-context.xml` to `root-context.xml` and autowired started to work. – Ali Aug 16 '11 at 13:54
  • You probably should read up on how Spring DI works, there is no magic, you need to tell Spring, either through explicit `` declarative syntax, or `` instructions, where your beans are that you want it to inject. This is true both in Spring Security and Spring Core. – Peter Mularien Aug 17 '11 at 13:39
  • Yep. Did the trick :) – Storm Oct 17 '15 at 16:07

2 Answers2

2

To manually wire the beans, just do the following:

<bean id="customUserDetailsService" 
      class="com.groupdealclone.app.service.AccountService" >
    <property name="accountDao" ref="accountDao" />
</bean>
beny23
  • 34,390
  • 5
  • 82
  • 85
  • Thanks Beny23. I managed to wire up the accountDao bean and it works fine, however the in AccountDao `@PersistenceContext EntityManager em;` was still null. I moved my hibernate config from application context to spring context and everthing works. Any idea if this is the right approach? – Ali Aug 16 '11 at 13:47
  • If I understand your setup correctly, you have a separate context for security and your application, which will mean that they can't see each other's beans. Are you going to be needing your accountDao in the application context? – beny23 Aug 16 '11 at 13:53
2

@Autowired works just fine inside an UserDetailsService implementation. Something else must be wrong: your injected interface may not be in a scanned package, or something else.

atrain
  • 9,139
  • 1
  • 36
  • 40
  • You would think, however UserDetailsService is in the same package as all other services and they work fine. – Ali Aug 16 '11 at 13:42
  • They all inject AccountDAO without issue? – atrain Aug 16 '11 at 13:51
  • Thanks Aaron, you were sorta right, I copied the component-scan from `servlet-context.xml` to `root-context.xml` and it works fine. Don't know if this is correct implementation though. – Ali Aug 16 '11 at 13:53